I am programming a boggle game board solver. It uses a Stack, a 2D Array Grid of letters for the game board that are read in from a .dat/.txt file, and Search "States" to store where its been, specifically (point coordinates, word so far). It is designed to search every possible letter combination on the board to form strings of length 3 or more, and then checks a dictionary file to see if that word is a valid boggle word solution. After, it stores the word and returns a list of solutions to the game board that was given in the arguments.
My Problem: For some reason this program has eluded me like no other thing I've ever written before. I am very new to the concept of "states" so that could be an underlying issue. I believe that what I have is fairly close to working, I am just at a loss for what could be wrong with it. The current issue is that it is not ever storing the current letter and building strings as it checks neighboring letters. It does check neighbors properly, but no strings are built. Here is the code:
BoggleSearch:
contains the main method, acts as the driver class.
import java.io.*;
import java.util.*;
public class BoggleSearch {
protected static int GRID_SIZE = 4;
public static String[][] grid = new String[GRID_SIZE][GRID_SIZE];
public static void main(String[] args) throws FileNotFoundException {
if (args.length != 1) {
System.err.println("Usage: java BoggleSearch gridFile");
System.exit(1);
}
Scanner scan = new Scanner(new File(args[0]));
String bigString = scan.next();
bigString = bigString+scan.next();
bigString = bigString+scan.next();
bigString = bigString+scan.next();
scan.close();
int count = 0;
for (int i = 0; i < GRID_SIZE; i++) {
for (int j = 0; j < GRID_SIZE; j++) {
grid[i][j] = bigString.substring(count, count);
count++;
}
}
WordSearch ws = new WordSearch(grid);
ArrayList<BoggleSearchState> foundWords = ws.startSearch();
System.out.println(foundWords);
}
}
WordSearch:
contains all of the algorithms that find that string every possible combination of letters possible on the given game board and cross-check them with the dictionary class.
import java.awt.Point;
import java.util.*;
public class WordSearch {
public static Stack<BoggleSearchState> stack;
public static ArrayList<BoggleSearchState> foundWords;
private String[][] grid;
private static final int GRID_SIZE = 4;
public BoggleDictionary dictionary;
public WordSearch(String[][] inputGrid) {
grid = new String[GRID_SIZE][GRID_SIZE];
stack = new Stack<BoggleSearchState>();
foundWords = new ArrayList<BoggleSearchState>();
inputGrid = new String[GRID_SIZE][GRID_SIZE];
try {
dictionary = new BoggleDictionary();
} catch (Exception e) {
System.err.println("blew up while making dict object");
e.printStackTrace();
}
}
public ArrayList<BoggleSearchState> startSearch() {
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid.length; j++) {
BoggleSearchState b = new BoggleSearchState(
new ArrayList<Point>(), grid[i][j]);
Point p = new Point(i, j);
b.path.add(p);
stack.push(b);
while (!stack.isEmpty()) {
BoggleSearchState s = stack.pop();
if (s.getWord().length() >=1 && dictionary.contains(s.getWord())) {
foundWords.add(s);
}
Point loc = s.path.get(s.path.size() - 1);
p = new Point(loc.x,loc.y);
// Bottom Neighbor
if (loc.x + 1 >= 0 && loc.x + 1 < grid.length && loc.y >= 0
&& loc.y < grid.length) {
if (s.getVisited(new Point(p.x+1,p.y)) != true) {
BoggleSearchState neo = new BoggleSearchState(new ArrayList<Point>(),s.getWord() + grid[loc.x + 1][loc.y]);
neo.path.add(new Point(p.x+1,p.y));
stack.push(neo);
}
}
// Top Neighbor
if (loc.x - 1 >= 0 && loc.x - 1 < grid.length && loc.y >= 0
&& loc.y < grid.length) {
if (s.getVisited(new Point(p.x-1,p.y)) != true) {
BoggleSearchState neo = new BoggleSearchState(
new ArrayList<Point>(),s.getWord() +
grid[loc.x - 1][loc.y]);
neo.path.add(new Point(p.x-1,p.y));
stack.push(neo);
}
}
// Right Neighbor
if (loc.x >= 0 && loc.x < grid.length && loc.y + 1 >= 0
&& loc.y + 1 < grid.length) {
if (s.getVisited(new Point(p.x,p.y+1)) != true) {
BoggleSearchState neo = new BoggleSearchState(
new ArrayList<Point>(),s.getWord() +
grid[loc.x][loc.y + 1]);
neo.path.add(new Point(p.x,p.y+1));
stack.push(neo);
}
}
// Left Neighbor
if (loc.x >= 0 && loc.x < grid.length && loc.y - 1 >= 0
&& loc.y - 1 < grid.length) {
if (s.getVisited(new Point(p.x,p.y-1)) != true) {
BoggleSearchState neo = new BoggleSearchState(
new ArrayList<Point>(),s.getWord() +
grid[loc.x][loc.y - 1]);
neo.path.add(new Point(p.x,p.y-1));
stack.push(neo);
}
}
// Bottom-Right Neighbor
if (loc.x + 1 >= 0 && loc.x + 1 < grid.length
&& loc.y + 1 >= 0 && loc.y + 1 < grid.length) {
if (s.getVisited(new Point(p.x+1,p.y+1)) != true) {
BoggleSearchState neo = new BoggleSearchState(
new ArrayList<Point>(),s.getWord() +
grid[loc.x + 1][loc.y + 1]);
neo.path.add(new Point(p.x+1,p.y+1));
stack.push(neo);
}
}
// Bottom-Left Neighbor
if (loc.x + 1 >= 0 && loc.x + 1 < grid.length
&& loc.y - 1 >= 0 && loc.y - 1 < grid.length) {
if (s.getVisited(new Point(p.x+1,p.y-1)) != true) {
BoggleSearchState neo = new BoggleSearchState(
new ArrayList<Point>(),s.getWord() +
grid[loc.x + 1][loc.y - 1]);
neo.path.add(new Point(p.x+1,p.y-1));
stack.push(neo);
}
}
// Top-Right Neighbor
if (loc.x - 1 >= 0 && loc.x - 1 < grid.length
&& loc.y + 1 >= 0 && loc.y + 1 < grid.length) {
if (s.getVisited(new Point(p.x-1,p.y+1)) != true) {
BoggleSearchState neo = new BoggleSearchState(
new ArrayList<Point>(),s.getWord() +
grid[loc.x - 1][loc.y + 1]);
neo.path.add(new Point(p.x-1,p.y+1));
stack.push(neo);
}
}
// Top-Left Neighbor
if (loc.x - 1 >= 0 && loc.x - 1 < grid.length
&& loc.y - 1 >= 0 && -1 < grid.length) {
if (s.getVisited(new Point(p.x-1,p.y-1)) != true) {
BoggleSearchState neo = new BoggleSearchState(
new ArrayList<Point>(),s.getWord() +
grid[loc.x - 1][loc.y - 1]);
neo.path.add(new Point(p.x-1,p.y-1));
stack.push(neo);
}
}
}
}
}
return foundWords;
}
}
BoggleSearchState:
Creates a state object that is used to store necessary data for each instance of a string forming path on the game board. contains methods necessary for its purpose.
import java.awt.Point;
import java.util.ArrayList;
public class BoggleSearchState {
private String word="";
public ArrayList<Point> path = new ArrayList<Point>();
public BoggleSearchState(ArrayList<Point>path, String word) {
this.path = path;
this.word = word;
}
public String getWord() {
return word;
}
public ArrayList<Point> getLocation() {
return path;
}
public boolean getVisited (Point p) {
ArrayList<Point> newPath = new ArrayList<Point>();
for (Point s: path) {
newPath.add(s);
if (p.equals(s)) {
return true;
}
}
return false;
}
public String toString() {
return this.word;
}
}
BoggleDictionary:
The terribly written dictionary class that was given for the assignment. It is tested and fully functional however.
// BoggleDictionary.java
import java.io.File;
import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.io.IOException;
import java.util.Scanner;
import java.util.HashSet;
import java.util.Iterator;
/**
A class that stores a dictionary containing words that can be used in a
Boggle game.
#author Teresa Cole
#version CS221 Fall 2013
*/
public class BoggleDictionary
{
private HashSet<String> dictionary;
/** Create the BoggleDictionary from the file dictionary.dat
*/
#SuppressWarnings("unchecked")
public BoggleDictionary() throws Exception {
ObjectInputStream dictFile = new ObjectInputStream(
new FileInputStream( new File( "dictionary.dat")));
dictionary = (HashSet<String>)dictFile.readObject();
dictFile.close();
}
/** Check to see if a string is in the dictionary to determine whether it
* is a valid word.
* #param word the string to check for
* #return true if word is in the dictionary, false otherwise.
*/
public boolean contains( String word)
{
return dictionary.contains( word);
}
/** Get an iterator that returns all the words in the dictionary, one at a
* time.
* #return an iterator that can be used to get all the words in the
* dictionary.
*/
public Iterator<String> iterator()
{
return dictionary.iterator();
}
/**
Main entry point
*/
static public void main(String[] args)
{
System.out.println( "BoggleDictionary Program ");
Scanner kbd = new Scanner( System.in);
BoggleDictionary theDictionary=null;
try
{
theDictionary = new BoggleDictionary();
}
catch (Exception ioe)
{
System.err.println( "error reading dictionary");
System.exit(1);
}
String word;
/*
while (kbd.hasNext())
{
word = kbd.next();
if (theDictionary.contains( word))
System.out.println( word + " is in the dictionary");
else
System.out.println( word + " is not in the dictionary");
}
*/
Iterator<String> iter = theDictionary.iterator();
while (iter.hasNext())
System.out.println( iter.next());
}
}
I would appreciate any help on this as I am really struggling with it at this point. I understand that there are numerous ways to implement other data structures or organization methods to accomplish this task in a much more efficient run-time. However the concern of the assignment is not catered towards efficiency, rather the underlying principles of using these data structures (stacks etc.) and understanding how you are able to go a wrong direction and then safely back track and go a new direction without the program crashing. Thank you in advance, any questions I'll try to answer as fast as I can.
As near as I can tell, you have two grids in WordSearch, but you set both of them to initialized arrays. You never use the grid you look like you might have built in the main method.
But it is hard to tell.
You have given us much data but little information. We don't need details about the entirety of a program, even one this size; we need to know what your specific question is. No one is liable to debug this for you, and in fact few enough are going to read as much of it as I have.
After you've fixed your initialization problem, debug your program however you can and figure out where it does something that (1) it isn't supposed to, and (2) you don't understand. You need to spend enough time attempting to figure out #1 yourself for your own education on debugging, and it makes it much more likely that you can explain what you don't understand and get a good answer to a specific question. "It isn't Building Strings" doesn't go quite far enough; WHERE isn't it building, what do you mean by building strings, etc. I expect it's because it has no input, but I didn't analyze that far.
Related
I'm trying to write an AI that never loses at Tic Tac Toe, and I want to use the minimax algorithm to do so. However, when I try to run the program, a stack overflow appears and I can't seem to find what is the error. Could you take a look and tell me what I'm doing wrong? It doesn't go as deep in the recursion I believe, since it should only go through all the possible game outcomes, which go up to 8 moves (since the player is first to play, not the AI). It is probably me doing something wrong, but I can't find anything.
EDIT: Here's the full code, the mechanics function is the main part:
EDIT2: Fixed the constructor
package Packet;
import java.util.*;
import java.util.Scanner;
public class Logic {
public static class TicTacToe{
private int[] currentBoard = new int[9];
private int[] availableSpots = new int [9];
private int emptySpace = 0;
private int playerAI = 1;
private int playerHuman = 2;
void TicTacToe(){
for (int i = 0; i < 9; i++){
this.currentBoard[i] = this.emptySpace;
}
for (int i = 0; i < 9; i++){
this.availableSpots[i] = i;
}
}
private int movesNumber(){
int counter = 0;
for (int i = 0; i < 9; i++){
if (this.currentBoard[i] == this.emptySpace){
counter++;
}
}
return counter;
}
private boolean win(int[] board,int player){
if (
(board[0] == player && board[1] == player && board[2] == player) ||
(board[3] == player && board[4] == player && board[5] == player) ||
(board[6] == player && board[7] == player && board[8] == player) ||
(board[0] == player && board[3] == player && board[6] == player) ||
(board[1] == player && board[4] == player && board[7] == player) ||
(board[2] == player && board[5] == player && board[8] == player) ||
(board[0] == player && board[4] == player && board[8] == player) ||
(board[2] == player && board[4] == player && board[6] == player) ){
return true;
}
else{
return false;
}
}
private int mechanics(int[] newBoard, int player){
if (win(newBoard,this.playerHuman)){
return -10;
}
else if (win(newBoard, this.playerAI)){
return +10;
}
else if (this.movesNumber() == 0){
return 0;
}
ArrayList<Integer> moves = new ArrayList<Integer>();
ArrayList<Integer> scores = new ArrayList<Integer>();
for (int i = 0; i < this.movesNumber(); i++){
int[] possibleBoard = new int[9];
possibleBoard = newBoard;
int availableSpotNumber = i;
int j = i;
while (this.availableSpots[j] == 9){
availableSpotNumber++;
j++;
}
possibleBoard[availableSpotNumber] = player;
if (player == this.playerAI){
scores.add(this.mechanics(possibleBoard, this.playerHuman));
}
else{
scores.add(this.mechanics(possibleBoard, this.playerAI));
}
moves.add(availableSpotNumber);
possibleBoard[availableSpotNumber] = this.emptySpace;
}
int bestMove = 0;
if (player == this.playerAI){
int bestScore = -10000;
for (int i = 0; i < moves.size(); i++){
if (scores.get(i) > bestScore){
bestScore = scores.get(i);
bestMove = i;
}
}
}
else {
int bestScore = 10000;
for (int i = 0; i < moves.size(); i++){
if (scores.get(i) < bestScore){
bestScore = scores.get(i);
bestMove = i;
}
}
}
return moves.get(bestMove);
}
public void printTable(){
System.out.println(this.currentBoard[0] + " | " + this.currentBoard[1] + " | " + this.currentBoard[2]);
System.out.println("- - -");
System.out.println(this.currentBoard[3] + " | " + this.currentBoard[4] + " | " + this.currentBoard[5]);
System.out.println("- - -");
System.out.println(this.currentBoard[6] + " | " + this.currentBoard[7] + " | " + this.currentBoard[8]);
System.out.println();
}
private void fillTable(int position,int player){
this.currentBoard[position] = player;
this.availableSpots[position] = 9;
}
public void startGame(){
while(true){
this.printTable();
Scanner ulaz = new Scanner(System.in);
fillTable(ulaz.nextInt(), this.playerHuman);
this.printTable();
fillTable(this.mechanics(this.currentBoard, this.playerAI), this.playerAI);
ulaz.close();
}
}
public void resetGame(){
for (int i = 0; i < 9; i++){
this.currentBoard[i] = this.emptySpace;
}
for (int i = 0; i < 9; i++){
this.availableSpots[i] = i;
}
}
}
public static void main(String[] args){
TicTacToe game = new TicTacToe();
game.startGame();
}
}
Also, here's the exact errors I get:
Exception in thread "main" java.lang.StackOverflowError
at Packet.Logic$TicTacToe.mechanics(Logic.java:54)
at Packet.Logic$TicTacToe.mechanics(Logic.java:84)
at Packet.Logic$TicTacToe.mechanics(Logic.java:87)
at Packet.Logic$TicTacToe.mechanics(Logic.java:84)
at Packet.Logic$TicTacToe.mechanics(Logic.java:87)
at Packet.Logic$TicTacToe.mechanics(Logic.java:84)
at Packet.Logic$TicTacToe.mechanics(Logic.java:87)
After this part, these parts appear a bunch of times (at least 50)
at Packet.Logic$TicTacToe.mechanics(Logic.java:84)
at Packet.Logic$TicTacToe.mechanics(Logic.java:87)
Line 54:
if (win(newBoard,this.playerHuman)){
Line 84:
scores.add(this.mechanics(possibleBoard, this.playerHuman));
Line 87:
scores.add(this.mechanics(possibleBoard, this.playerAI));
This might or might not be a code issue, as Java is not a fully functional language with it comes to recursion, you might want to see this answer: Does Java 8 have tail call optimization?
Basically, a language that allows for unlimited-depth recursion has to have tail recursion optimization. With tail call optimization, if the return value is the result of exactly the same function with different parameters, the stack will get replaced instead of the new call being added to the stack.
If a language does not have tail call optimization, then you're limited by stack size in how deep your recursion goes, even if the recursive calls have correct termination conditions (note: I haven't analyzed the code in depth, so obviously there might be a problem in the recursive logic itself). If you want to tweak the stack size, use the -Xss Java runtime parameter. Generally, increasing the stack size is a good heuristic (although not a fool-proof method) of checking whether the fault is with the language or with your algorithm.
There's a couple of problems, but here's how you can debug this:
add a StringBuilder debug = new StringBuilder(); field to your class, then change the main loop like this:
int debugLen = debug.length();
debug.append("\nSetting ").append(availableSpotNumber).append(" to ").append(player);
possibleBoard[availableSpotNumber] = player;
try {
if (player == this.playerAI) {
scores.add(this.mechanics(possibleBoard, this.playerHuman));
} else {
scores.add(this.mechanics(possibleBoard, this.playerAI));
}
moves.add(availableSpotNumber);
} catch (StackOverflowError error) {
throw new StackOverflowError(debug.toString());
}
debug.setLength(debugLen);
possibleBoard[availableSpotNumber] = this.emptySpace;
Then you will see what is happening, which will give you a clue what to fix next. For example, the current version is doing this, for initial human move 1:
Setting 0 to 1
Setting 0 to 2
Setting 0 to 1
Setting 0 to 2
etc..
But, if you're too lazy, you can find a fixed version here.
I cannot find my exception although the errors are at
at puzzle.Puzzle.isSafe(Puzzle.java:97)
at puzzle.Puzzle.main(Puzzle.java:49)
Java Result: 1
I need to print a 15x 15 grid with random words in 6 directions and starts in empty spaces.
My java code is as follows.
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package puzzle;
//import java.util.Arrays;
import java.util.Random;
/**
*
* #author sony
*/
public class Puzzle {
static char[][] grid;
//class solve= new Puzzle();
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
grid =new char[15][15];
String[] words={"hello","coward","heartbeat","beautiful","kind"};
String[] direction = {"horizontal","horizontalBack","vertical","varticalUp",
"diagonal","diagonalBack"};
int i,j,x,y,dir;
Random randGen = new Random();
for(i=0; i<15 ;i++)
{
for(j=0;j<15;j++)
grid[i][j]='*';
}
for(i=0;i< words.length;i++)
{
int set=0;
while(set!=1)
{
x = randGen.nextInt(15);
y = randGen.nextInt(15);
dir = randGen.nextInt(6);
if((isSafe(x,y,words[i],direction[dir])))
{
place(x,y,words[i],direction[dir]);
set=1;
}
}
}
for(i=0; i<15; i++)
{
for(j=0;j<15;j++)
System.out.print(grid[i][j]);
System.out.println("");
}
}
static boolean isSafe(int x,int y, String word, String d)
{ int len=word.length();
int i,k,j;
if(d.equals("horizontal"))
for(i=y,k=0;i< (y+len);i++,k++)
{
if((grid[x][i]!='*')&& (grid[x][i]!=word.charAt(k)) && ((y+len) >15) )
return false;
}
if(d.equals("horizontalBack"))
for(i=y,k=0;i >(y-len);i--,k++)
{
if((grid[x][i]!='*')&& (grid[x][i]!=word.charAt(k)) && ((y-len) <0) )
return false;
}
if(d.equals("vertical"))
for(i=x,k=0;i <(x+len);i++,k++)
{
if((grid[i][y]!='*')&& (grid[i][y]!=word.charAt(k)) && ((x+len) >15) )
return false;
}
if(d.equals("verticalUp"))
for(i=x,k=0;i >(x+len);i++,k++)
{
if((grid[i][y]!='*')&& (grid[i][y]!=word.charAt(k)) && ((x-len) <0) )
return false;
}
if(d.equals("diagonal"))
{ k=0;i=y;j=x;
while((i< (y+len)) && (j< x+len)) {
if((grid[i][j]!='*')&& (grid[i][j]!=word.charAt(k)) && ((x+len) >15) && ((y+len)>15) )
{return false;}
i++;j++;k++;
}
}
if(d.equals("diagonalBack"))
{ k=0;i=y;j=x;
while((i> (y-len)) && (j>x-len)) {
if((grid[i][j]!='*')&& (grid[i][j]!=word.charAt(k)) && ((x-len)<0) && ((y-len)<0) )
{return false;}
i--;j--;k++;
}
}
return true;
}
static void place(int x, int y, String word, String d)
{ int len = word.length();
int i,k,j;
if(d.equals("horizontal"))
for( i=y, k=0;i< (y+len);i++,k++)
{
grid[x][i]=word.charAt(k);
}
if(d.equals("horizontalBack"))
for( i=y,k=0;i> (y-len);i--,k++)
{
grid[x][i]=word.charAt(k);
}
if(d.equals("vertical"))
for( i=x,k=0;i< (x+len);i++,k++)
{
grid[i][y]=word.charAt(k);
}
if(d.equals("verticalUp"))
for( i=x,k=0;i> (x-len);i--,k++)
{
grid[i][y]=word.charAt(k);
}
if(d.equals("diagonal"))
{ i=y;j=x;k=0;
while((i< (y+len)) && (j< (x+len)))
{
grid[i][j]=word.charAt(k);
i++;j++;k++;
}
}
if(d.equals("diagonalUp"))
{ i=y;j=x;k=0;
while((i> (y-len)) && (j> (x-len)))
{
grid[i][j]=word.charAt(k);
i--;j--;k++;
}
}
}
}
Instead of telling you how to fix your code, I'll help you understand the error.
Log
at puzzle.Puzzle.isSafe(Puzzle.java:97)
at puzzle.Puzzle.main(Puzzle.java:49)
Java Result: 1
Puzzle.java:97
if (grid[i][j]!='*' && grid[i][j]!=word.charAt(k) && (x+len)>15 && (y+len)>15)
Exception
Exception java.lang.ArrayIndexOutOfBoundsException means that either:
i >= grid.length
j >= grid[i].length
Detail
grid.length and grid[i].length are determined when the array is created:
grid = new char[15][15];
grid.length is 15
grid[i].length is 15
Moreover
Also, there is the string word:
for (i=y, k=0; i < (y+len); i++, k++)
word.charAt(k);
This will cause an issue too, when k at some point becomes k >= word.length() so that loop should be like this:
for (i=y, k=0; i < (y+len) && k < word.length(); i++, k++)
word.charAt(k);
I can see two bugs.
(1) The line that reads
for(i=x,k=0;i >(x+len);i++,k++)
should read
for(i=x,k=0;i >(x-len);i--,k++)
I think it's line 89.
(2) The bug that's causing this exception is the fact that every time you've got a whole lot of conditions separated by &&, the first one should be && and the subsequent ones should be ||.
For example,
if((grid[x][i]!='*')&& (grid[x][i]!=word.charAt(k)) && ((y+len) >15)) {
should read
if((grid[x][i]!='*')&& (grid[x][i]!=word.charAt(k)) || ((y+len) >15)) {
because you need to return that this square is an unsafe place to start the word if y + len > 15 regardless of what is found at each of the grid squares that you're checking. Similarly, with all the other conditions that look like this.
Please note the typo. varticalUp in the array declaration and verticalUp in the if condition. Although this is not the cause of the problem but its worth noting it.
I just quickly went through your code and it seems that the problem is in your variable len. See the statement int len=word.length(); on line 68. In fact it should be int len=word.length()-1; because the array index starts from 0. I have not tested it, but you can give it a try.
public String tictactoe(String game)
{
game = game.toUpperCase();
char[][] board = new char[3][3];
int loc = 0;
for( char r = 0; r < board.length; r++ )
{
for( char c = 0; c < board[r].length; c++)
{ board[r][c] = game.charAt(loc);
loc++;
}
}
if ((board[0][0] =='X' && board[0][1] =='X' && board[0][2] =='X') ||
(board[1][0] =='X' && board[1][1] =='X' && board[1][2] =='X') ||
(board[2][0] =='X' && board[2][1] =='X' && board[2][2] =='X'))
return("Player 1 wins horizontally!");
else if ((board[0][0] =='O' && board[0][1] =='O' && board[0][2] =='O') ||
(board[1][0] =='O' && board[1][1] =='O' && board[1][2] =='O') ||
(board[2][0] =='O' && board[2][1] =='O' && board[2][2] =='O'))
return("Player 2 wins horizontally!");
else if ((board[0][0] =='X' && board[1][0] =='X' && board[2][0] =='X') ||
(board[0][1] =='X' && board[1][1] =='X' && board[2][1] =='X') ||
(board[0][2] =='X' && board[1][2] =='X' && board[2][2] =='X'))
return("PLayer 2 wins vertically!");
else if ((board[0][0] =='O' && board[1][0] =='O' && board[2][0] =='O') ||
(board[0][1] =='O' && board[1][1] =='O' && board[2][1] =='O') ||
(board[0][2] =='O' && board[1][2] =='O' && board[2][2] =='O'))
return("Player 2 wins vertically!");
return "Tie!";
}
Above is my code for this method. It reads in a 9 letter string for a tic-tac-toe game and then puts it one by one into a 2D array. I unfortunately have to use this method because this is unfortunately what we're learning, and I've continuously had to bother my teacher about this...
The if statements check each row and column for a winner (I realize it does not check the horizontals). My issue here is nothing is being returned, even though it is supposed to return a string. As I have said I have to use 2D-arrays here. The goal is to check a tic-tac-toe game and return whom as won.
Consider replacing each instance of this
if(board[0][0] =='X' && board[0][1] =='X' && board[0][2] =='X') ||
...
With this function:
public boolean isRowFilledWith(int row_index, char x_or_o) {
return (board[row_idx][0] == x_or_o &&
board[row_idx][1] == x_or_o &&
board[row_idx][2] == x_or_o);
}
Now, to see if the top-most row contains all x-s, call it with
if(isRowFilledWith(0, 'X') ||
...
This will make your code a lot more concise, easier to read and easier to debug.
Try doing:
System.out.println(fooObject.tictactoe("XXXXXXOOO");
inside your main argument (public static void main(String[] args)
I suspect you've confused return and System.out.println. The console will not print anything if returned. Instead, returning is what is thrown at the computer after the function is called. Try printing the result of calling the function...THAT is what is returned to the computer and is only going to be visible if you print it. There may not be any error in your code.
First off, to directly answer your question:
Your function works fine, I locally tested it. I tried both horizontal, and vertical, with both x and o. It must be something you are doing with the caller.
The biggest problem with this code is clarity. You can do quite a bit about clarity by separating the logic into groups.
Clarity can be achieved by making application specific objects.
If you have an object to represent a move, a game, and the marker... you can drastically simplify you code and most of all make it easy to read and debug.
I went ahead and implemented tic tac toe just to kinda explain what I mean by clarity.
Any time you start having massive if else chains and block return statements you may need to take the extra time to break up the problem.
This is fully compililable and I think if you debug through it a few times you will find it is much easier to spot mistakes.
It is also easy to ajust the game... Right now, we have 2 players and a 3 by 3 game.
However, we have extra constructors to adjust the size of the game and to give the gamers some options on what they want thier tic tac toe game to look like.
The major reason to do this is for clarity and debugging.
It is always easier to find issues if you have problem specific methods and problem specific objects.
Below is a fully compilable console application for tic tac toe. In its current form, it plays 100 random 3 by 3 games and prints the results of all 100 games.
The application is also capable of taking your string input as console input and processing the moves.
Notice that we are still using two dimensional arrays, but we hidden away the complexity of using them by encapsulating the array in the Board object.
We also gave a move object so we can store moves to play later. This was useful in creating the loop to play many games, as all the facts about the move are contained in a single object.
Since we created three separate methods for validating the move input. We have a much clearer explanation of what we are validating and why we are doing it.
Most debuggers will also show the objects toString method, so by embedding the game display within the toString() we are allowed to see what the board looks like when we are debugging.
The trick to making clean code that doesn't require alot of comments is to attempt to split out any complexity to its own unit.
You probably will cover more about units of work later, but just keep it in mind, the more simple a method, the more reusable it is. The more single purpose a class is, the better and clearer it is.
My Example:
Mark.java
-This enum is the representation of the mark used by a player to signify their move.
public enum Mark{
X, Y;
}
TicTacToe.java
-This class is your main class
it handles gathering user input, cleaning it, processing it, and displaying the output to the user
Notice that I am not doing game display anywhere else but the main method. this keeps all display issues localized to one spot. The advantage to breaking up your code into specific objects is knowing where to fix something when it breaks.
package com.clinkworks.example;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.clinkworks.example.Move;
import com.clinkworks.example.Board;
import com.clinkworks.example.Mark;
public class TicTacToe {
//this variable is simply used for output. Since we cant save CAT in the mark enum, we
// use it to hold cats games.
private static final String catsGameIdentity = "CAT";
//this map contains the counts of wins for each symbol
//it also keeps track of ties and stores it in the map as "CAT"
//soo.. gamesToWinsMap.get("CAT") will produce the amount of ties.
private static final Map<String, Integer> gamesToWinsMap = new HashMap<String, Integer>();
public static void main(String[] args){
String game = args[0].toUpperCase(); //better ways to do this and no validation here.. but it will work
Board board = new Board();
//holds our current place in the string passed in from teh console
int currentStringLocation = 0;
for(int row = 0; row < 3; row++){ //loop through the rows
for(int column = 0; column < 3; column++){ //for each row loop through the columns
if(gameOver(board)){ // we don't care about the rest of the input if the game was won
break;
}
//convert the symbol to a string for use in teh ValueOf function in the enum class
String symbol = "" + game.charAt(currentStringLocation); //better than String.valueOf imho
//allow spaces to represent un marked places
if(" ".equals(symbol)){
currentStringLocation++; //this accounts for spaces in our input
break;
}
//convert the string to a Mark enum... over use of strings is a very very bad practice
Mark nextMarkToPlace = Mark.valueOf(symbol);
Move move = new Move(row, column, nextMarkToPlace); //we create a move object that encapsulates the complexity of placing the mark on the game board
board.play(move); //the game already knows how to play itself, just let it
currentStringLocation++; //increment the posision.
}
}
//since you may not have won the game, or gave a complete string for a cats game,
// lets at least display the board for debugging reasons.
if(board.movesLeft() > 0){
System.out.println("Board isn't finished, but here is what it looks like basd on your input: ");
System.out.println(board);
}
}
//call me main if you want to see what I do
public static void main2(String[] args) {
//lets play 100 games and see the wins and ties
playGames(100);
System.out.println("Number wins by X: " + gamesToWinsMap.get(Mark.X.name()));
System.out.println("Number wins by O: " + gamesToWinsMap.get(Mark.O.name()));
System.out.println("Number of ties: " + gamesToWinsMap.get(catsGameIdentity));
}
public static void playGames(int count) {
//play a new game each iteration, in our example, count = 100;
for (int i = 0; i < count; i++) {
playGame();
}
}
public static void playGame() {
//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();
//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 < 3; row++) {
for (int col = 0; col < 3; 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("Player with the mark: " + board.whoWon() + " won the game!");
System.out.println(board);
Integer winCount = gamesToWinsMap.get(board.whoWon().name());
winCount = winCount == null ? 1 : winCount + 1;
gamesToWinsMap.put(board.whoWon().name(), winCount);
return true;
} else if (board.movesLeft() == 0) {
System.out.println("It was a cats game!!");
System.out.println(board);
Integer catCount = gamesToWinsMap.get(catsGameIdentity);
catCount = catCount == null ? 1 : catCount + 1;
gamesToWinsMap.put(catsGameIdentity, catCount);
return true;
}
return false;
}
Move.java
-This class is responsible for ensuring that only integers are passed to the game board
and for telling the game board who is doing the move (optional)
package com.clinkworks.example;
import com.clinkworks.example.Mark;
public class Move {
private int row;
private int column;
private Mark forcedMark;
public Move(int row, int column) {
this.row = row;
this.column = column;
}
//the board already knows who should be next. only use this constructor to override
// what symbol to put on the game board
public Move(int row, int column, Mark markToPlace){
this.row = row;
this.column = column;
forcedMark = markToPlace;
}
public int getRow() {
return row;
}
public int getColumn() {
return column;
}
public Mark getMark(){
return forcedMark;
}
}
Board.java
-This is where all the state of the board is managed, who is the next player, who won, and
is there any moves left to play. It also ensures that only valid moves are played.
package com.clinkworks.example;
import com.clinkworks.example.Mark;
import com.clinkworks.example.Move;
public class Board {
private final int rowSize;
private final int columnSize;
private final Mark[][] gameBoard;
private Mark currentMark;
private Mark winningMark;
/**
* This constructor defaults the starting player to X with a 3 by 3
* game.
*/
public Board() {
gameBoard = new Mark[3][3];
currentMark = Mark.X; // X always goes first ;P
winningMark = null;
this.rowSize = 3;
this.columnSize = 3;
}
/**
* This constructor defaults the starting player to X, and lets the
* board size be adjusted
*/
public Board(int rowSize, int columnSize) {
gameBoard = new Mark[rowSize][columnSize];
currentMark = Mark.X; // X always goes first ;P
winningMark = null;
this.rowSize = getRowSize();
this.columnSize = columnSize;
}
/**
* this constructor allows the players to choose who goes first on a 3
* by 3 board.
*
* #param firstPlayer
*/
public Board(Mark firstPlayer) {
gameBoard = new Mark[3][3];
currentMark = firstPlayer; // Let the player choose
winningMark = null;
rowSize = 3;
columnSize = 3;
}
/**
* this constructor allows the players to choose who goes first and to
* choose the size of the board.
*
* #param firstPlayer
*/
public Board(Mark firstPlayer, int rowSize, int columnSize) {
gameBoard = new Mark[getRowSize()][columnSize];
currentMark = firstPlayer; // Let the player choose
winningMark = null;
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 += getMarkAt(x, y) == null ? 1 : 0;
}
}
return moveCount;
}
/**
* If someone won, this will return the winning player.
*
* #return the winning player
*/
public Mark whoWon() {
return winningMark;
}
/**
* This move allows the next player to choose where to place their mark.
* if a move is played without a player given, it will use the current player variable
*
* as a side affect, the next player in rotation is chosen.
*
* #param Move
* #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("Cannot play " + currentMark + " at " + move.getRow() + ", " + move.getColumn() + "\n" + toString());
}
doMove(move);
boolean playerWon = isWinningMove(move);
if (playerWon) {
winningMark = currentMark;
return true;
}
togglePlayer();
boolean outOfMoves = movesLeft() <= 0;
return outOfMoves;
}
public Mark lastMarkPlayed() {
return currentMark;
}
public int getRowSize() {
return rowSize;
}
public int getColumnSize() {
return columnSize;
}
public Mark getCurrentPlayer() {
return currentMark;
}
public Mark getMarkAt(int row, int column) {
return gameBoard[row][column];
}
private void doMove(Move move) {
if(move.getMark() != null){
currentMark = move.getMark();
}
gameBoard[move.getRow()][move.getColumn()] = getCurrentPlayer();
}
private void togglePlayer() {
if (currentMark == Mark.X) {
currentMark = Mark.O;
} else {
currentMark = Mark.X;
}
}
/**
* A valid move is a move where the row and the column are within boundries
* and no move has been made that the location specified by the move.
*/
private boolean validMove(Move move) {
boolean noMarkAtIndex = false;
boolean indexesAreOk = move.getRow() >= 0 || move.getRow() < getRowSize();
indexesAreOk = indexesAreOk && move.getColumn() >= 0 || move.getColumn() < getColumnSize();
if (indexesAreOk) {
noMarkAtIndex = getMarkAt(move.getRow(), move.getColumn()) == null;
}
return indexesAreOk && noMarkAtIndex;
}
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++) {
Mark markOnCol = getMarkAt(move.getRow(), i);
if (markOnCol != getCurrentPlayer()) {
matchesColumn = false;
break;
}
}
return matchesColumn;
}
private boolean winsAcross(Move move) {
boolean matchesRow = true;
for (int i = 0; i < getRowSize(); i++) {
Mark markOnRow = getMarkAt(i, move.getColumn());
if (markOnRow != getCurrentPlayer()) {
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++) {
Mark markOnDiagnal = getMarkAt(i, i);
if (markOnDiagnal != 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();
}
//prints out the board in a nice to view display
public String toString() {
StringBuffer stringBuffer = new StringBuffer();
for(int y = 0; y < getColumnSize(); y++) {
for(int x = 0; x < getRowSize(); x++) {
Mark mark = getMarkAt(x, y);
String markToPrint = "";
if (mark == null) {
markToPrint = " ";
} else {
markToPrint = mark.name();
}
stringBuffer.append("|").append(markToPrint);
}
stringBuffer.append("|\n");
}
return stringBuffer.toString();
}
}
}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I'm not sure what's going on, but in the console I have a red 'stop' square that i can click to stop my program from running (Eclipse IDE) and my program is just running and the square stays red..?
EDIT:
my maze:
WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
WSOOOOOOOOOOOOOOWOOOOOOOOOOOOOOOOOWOOOOOOOOOOOOOOOWOOOOOOW
WWOOOOOOOOOOOOOWWWWWWWWWWWWWOOOOOOOOOOWWWWWWWWWWWWWOOOOOOW
WWWWWWOOOOOOOOOOOOWWWWWWWOOOOOOOOOOOOWWWWWWWWWWWWWWWWOOOOW
WOOOOOOWWWWWWWWWWWWWWOOOOOOOOOOOWWWWWWWWOOOOOOOOOOOOOOOWWW
WOOOOWWWWWWWOOOOOOWWWWOOOOOOWWWWWWWWWWWOOOOWWWWWWWWWOWWWWW
WOOOWWWWWWWWWWWWOOWWWWWWWWWWWWOOOOOOOOOOOOWWWWWWWWWOOOOOWW
WOOWWWWWWWWWWWWWOOWWWWWWWWWWWWWWWWWOOOOOOOWWWWWWWWWWWWOOOW
WOWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWOOOOOOOWWWWWWWWWWWOOW
WOWWWWWWWWWWWWWOOOOOOOOOOOOOOOOOOOOOOOOOOOOWWWWWWWWWWWWOOW
WOOOOOOOOOOOOOOOOWWWWOOOOOOOOWWWWWWWOOOOOOWWWWWWWWWWWWWWFW
WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
EDIT: here is my code:
import java.io.File;
import java.io.FileNotFoundException;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Stack;
import java.awt.Point;
public class MazeExplorer {
static Point startPoint = new Point();
static Point finishPoint = new Point();
final static int mazeHeight = 12;
final static int mazeWidth = 58;
static char[][] mazePoints = new char[mazeHeight][mazeWidth];
Stack<Point> pointsNotTraversed = new Stack<Point>();
Point pt = new Point();
static HashSet<Point> previousLocations = new HashSet<Point>();
static Stack<Point> nextPoints = new Stack<Point>();
public static void main(String[] args) throws FileNotFoundException{
System.out.println("Please enter the file name of your Maze");
Scanner console = new Scanner(System.in);
File f = new File(console.nextLine());
Scanner sc = new Scanner(f);
if(!sc.hasNextLine()){
System.out.println("Sorry, please enter a file name with the extension, that contains a maze!");
}
System.out.println("So, you want to know if your maze is solvable.....?");
for (int row = 0; row < mazeHeight && sc.hasNext(); row++) {
final String mazeRow = sc.next(); //Get the next row from the scanner.
mazePoints[row] = mazeRow.toCharArray(); //Convert the row into a char[].
}
//identify the finish point
for(int i = 0; i < mazeHeight; i++){
for(int j = 0; j<mazeWidth; j++){
if(mazePoints[i][j] == 'F'){
finishPoint = new Point(i, j);
}
}
}
// Identify the start point
for(int i = 0; i< mazeHeight; i++){
for(int j = 0; j < mazeWidth; j++){
if(mazePoints[i][j] == 'S'){
startPoint = new Point(i , j);
}
}
}
isTraversable(startPoint);
}
public static boolean isTraversable(Point current){
boolean isSolvable = false;
nextPoints.push(current);
do {
if(current.y < 11) {
if((mazePoints[current.y + 1][current.x] != ' ') && (mazePoints[current.y + 1][current.x] != 'W') ){ // below direction
nextPoints.push(new Point(current.y + 1, current.x));
mazePoints[current.y + 1][current.x] = ' ';
isTraversable(nextPoints.pop());
}
}
if(current.y > 0){
if (mazePoints[current.y - 1][current.x] != ' ' && mazePoints[current.y - 1][current.x] != 'W' ){ //up dir
nextPoints.push(new Point(current.y - 1, current.x));
mazePoints[current.y - 1][current.x] = ' '; //'X' marks where you've already been
isTraversable(nextPoints.pop());
}
}
if(current.x < 57){
if(mazePoints[current.y][current.x + 1] != ' ' && mazePoints[current.y][current.x + 1] != 'W'){ // to the right
nextPoints.push(new Point(current.y, current.x + 1));
mazePoints[current.y][current.x + 1] = ' ';
isTraversable(nextPoints.pop());
}
}
if(current.x > 0){
if(mazePoints[current.y][current.x - 1] != ' ' && mazePoints[current.y][current.x - 1] != 'W') { // to the left
nextPoints.push(new Point(current.y, current.x - 1));
mazePoints[current.y][current.x - 1] = ' ';
isTraversable(nextPoints.pop());
}
}
if(current.equals(finishPoint)){
isSolvable = true;
System.out.println("MAZE IS SOLVABLE, YAHOOOOOO!!!!");
}
} while(!current.equals('F') && !nextPoints.isEmpty());
return isSolvable;
}
}
As I suggested before, you just need to reconfigure your recursive method. I took the liberty of doing this but if you ever want to learn how to program you'll want to try and solve problems like these on your own. Or try to understand the logic of your solution before you start coding.
Your main problem is that you don't know what direction you want to go in with the method before you just jumped in and that was causing all sorts of errors with different things not being compatible with each other.
import java.io.File;
import java.io.FileNotFoundException;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Stack;
import java.awt.Point;
public class TestCode {
static Point startPoint = new Point();
static Point finishPoint = new Point();
final static int mazeHeight = 12;
final static int mazeWidth = 58;
static char[][] mazePoints = new char[mazeHeight][mazeWidth];
Stack<Point> pointsNotTraversed = new Stack<Point>();
Point pt = new Point();
static HashSet<Point> previousLocations = new HashSet<Point>();
static Stack<Point> nextPoints = new Stack<Point>();
public static void main(String[] args) throws FileNotFoundException{
System.out.println("Please enter the file name of your Maze");
Scanner console = new Scanner(System.in);
File f = new File(console.nextLine());
Scanner sc = new Scanner(f);
if(!sc.hasNextLine()){
System.out.println("Sorry, please enter a file name with the extension, that contains a maze!");
}
System.out.println("So, you want to know if your maze is solvable.....?");
for (int row = 0; row < mazeHeight && sc.hasNext(); row++) {
final String mazeRow = sc.next(); //Get the next row from the scanner.
mazePoints[row] = mazeRow.toCharArray(); //Convert the row into a char[].
}
//identify the finish point
for(int i = 0; i < mazeHeight; i++){
for(int j = 0; j<mazeWidth; j++){
if(mazePoints[i][j] == 'F'){
finishPoint = new Point(i, j);
}
}
}
// Identify the start point
for(int i = 0; i< mazeHeight; i++){
for(int j = 0; j < mazeWidth; j++){
if(mazePoints[i][j] == 'S'){
startPoint = new Point(i , j);
}
}
}
System.out.println(isTraversable(startPoint));
}
public static boolean isTraversable(Point current){
mazePoints[current.x][current.y] = ' ';
if(current.y < 56 && current.y > 0 && current.x > 0 && current.x < 11){
if (mazePoints[current.x - 1][current.y] == 'O'){ // Up dir
Point upPoint = new Point(current.x-1, current.y);
nextPoints.push(upPoint);
}
if(mazePoints[current.x+1][current.y] == 'O'){ // Down dir
Point downPoint = new Point(current.x+1, current.y);
nextPoints.push(downPoint);
}
if(mazePoints[current.x][current.y + 1] == 'O'){ // to the right
Point rightPoint = new Point(current.x, current.y+1);
nextPoints.push(rightPoint);
}
if(mazePoints[current.x][current.y - 1] == 'O'){ // to the left
Point leftPoint = new Point(current.x, current.y-1);
nextPoints.push(leftPoint);
}
if(mazePoints[current.x - 1][current.y] == 'F' ||
mazePoints[current.x + 1][current.y] == 'F' ||
mazePoints[current.x][current.y - 1] == 'F' ||
mazePoints[current.x][current.y + 1] == 'F'){
System.out.println("MAZE IS SOLVABLE, YAHOOOOOO!!!!");
return true;
}
}
if(nextPoints.isEmpty()){
return false;
}
else{
current = nextPoints.pop();
}
return(isTraversable(current));
}
}
With the maze input:
WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
WSOOOOOOOOOOOOOOWOOOOOOOOOOOOOOOOOWOOOOOOOOOOOOOOOWOOOOOOW
WWOOOOOOOOOOOOOWWWWWWWWWWWWWOOOOOOOOOOWWWWWWWWWWWWWOOOOOOW
WWWWWWOOOOOOOOOOOOWWWWWWWOOOOOOOOOOOOWWWWWWWWWWWWWWWWOOOOW
WOOOOOOWWWWWWWWWWWWWWOOOOOOOOOOOWWWWWWWWOOOOOOOOOOOOOOOWWW
WOOOOWWWWWWWOOOOOOWWWWOOOOOOWWWWWWWWWWWOOOOWWWWWWWWWOWWWWW
WOOOWWWWWWWWWWWWOOWWWWWWWWWWWWOOOOOOOOOOOOWWWWWWWWWOOOOOWW
WOOWWWWWWWWWWWWWOOWWWWWWWWWWWWWWWWWOOOOOOOWWWWWWWWWWWWOOOW
WOWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWOOOOOOOWWWWWWWWWWWOOW
WOWWWWWWWWWWWWWOOOOOOOOOOOOOOOOOOOOOOOOOOOOWWWWWWWWWWWWOOW
WOOOOOOOOOOOOOOOOWWWWOOOOOOOOWWWWWWWOOOOOOWWWWWWWWWWWWWOFW
WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
Yields the following output:
So, you want to know if your maze is solvable.....?
MAZE IS SOLVABLE, YAHOOOOOO!!!!
true
I imported the file a different way, but you can change that back to whatever method you use previously.
Might be that you've started multiple programs and you have the "Show Console When Standard Output Changes" Not sure, but that explains one scenario. If you start task manager and find the program there you could try terminating it that way.
If it's stuck running and never completes you could try running your program in the Eclipse debugger, without any breakpoints.
Open the Debug tab (Open in from Window > Show View > Debug), suspend the thread by right clicking 'Thread [main] (Running)' and selecting 'Suspend'.
Then work your way up from the bottom of the stack, hopefully this will narrow it down enough for you to find where it blocks.
import java.util.Scanner;
import java.util.Stack;
public class test5 {
private int numRows;
private int numCols;
public test5(){
Scanner input = new Scanner(System.in);
System.out.println("Enter number of rows: ");
numRows = input.nextInt();
System.out.println("Enter number of cols: ");
numCols = input.nextInt();
Stack<Point>stack = new Stack<Point>();
stack.push(new Point(0,0));
while(!stack.isEmpty()){
if(currentPath(stack.pop(),stack)){
System.out.println("Maze is solvable");
}
}
}
public static void main(String[]args){
new test5();
}
private boolean currentPath(Point point, Stack<Point>stack){
int currentRow = point.getRow();
int currentCol = point.getCol();
while(currentRow!=numRows-1 || currentCol!=numCols-1){
boolean canGoRight = canGoRight(currentRow,currentCol);
boolean canGoUp = canGoUp(currentRow,currentCol);
boolean canGoDown = canGoDown(currentRow,currentCol);
if(canGoRight){
if(canGoUp){
stack.push(new Point(currentRow-1,currentCol));
}
if(canGoDown){
stack.push(new Point(currentRow+1,currentCol));
}
currentCol = currentCol+1;
}
else{
if(canGoUp){
if(canGoDown){
stack.push(new Point(currentRow+1,currentCol));
}
currentRow = currentRow-1;
}
else if(canGoDown){
currentRow = currentRow+1;
}
else{
return false;
}
}
}
return true;
}
private boolean canGoUp(int row, int col){
return row-1>=0;
}
private boolean canGoRight(int row, int col){
return col+1<numCols;
}
private boolean canGoDown(int row, int col){
return row+1<numRows;
}
class Point{
private int row;
private int col;
public Point(int row, int col){
this.row = row;
this.col = col;
}
public int getRow(){
return row;
}
public int getCol(){
return col;
}
}
}
I have a .txt file with following format data(co-ordinates)
0 1 12.56
2 0 -56.2
1 2 78.2
0 -56.2 2
-2 8 0
I imported this data into using the following code.
public ArrayList<Point3d> loadFile(String filename) {
ArrayList<Point3d> words = new ArrayList<Point3d>();
try {
Scanner chopper = new Scanner(new File(filename));
while (chopper.hasNext()) {
double x=chopper.nextDouble();
double y=chopper.nextDouble();
double z=chopper.nextDouble();
Point3d p=new Point3d(x, y, z);
words.add(p);
// just calling nextLine will cause an exception at the end of the file unless you have an blank line there on purpose, so this makes sure it does
}
chopper.close();
} catch (Exception e) {
System.out.println(e);
}
return words;
}
importing is working fine.Know I want to separate negative, positive coordinates also I want to append their corresponding index values.
Finally I want result in the following way.
Result :
positiveList= {{0,0,1,12.56},{2,1,2,78.2}}
negativeList={{1,2,0,-56.2},{3,0,-56.2,2},{4,-2,8,0}}
How can I do this.
My solution here uses the Map data structure, but you can create 2 Lists of Lists if you wish.
Outside the while loop add:
Map<Integer, Point3D> negativeCoord = new HashMap<>();
Map<Integer, Point3D> positivetiveCoord = new HashMap<>();
int currentIndex = 0;
and inside it:
Point3d p = new Point3d(x, y, z);
if(x < 0 || y < 0 || z < 0) {
negativeCoord.put(currentIndex, p);
} else {
positiveCoord.put(currentIndex, p);
}
currentIndex++;
You could do this after loading the file, like so:
Map<Integer, Point3d> positiveList = new java.util.HashMap<Integer, Point3d>();
Map<Integer, Point3d> negativeList = new java.util.HashMap<Integer, Point3d>();
for (int i = 0; i < words.size(); i++) {
Point3d p = words.get(i);
if (p.x < 0 || p.y < 0 || p.z < 0) {
negativeList.put(i + 1, p);
} else {
positiveList.put(i + 1, p);
}
}
or integrate the above in your while-loop, what saves you from iterating over all the words twice.
This would be the solution to just have the positives and negatives, without knowing their order.
public ArrayList<Point3D> getPositives(ArrayList<Point3D> points) {
ArrayList<Point3D> positives = new ArrayList<>();
for(Point3D next : points) {
if(next.getX() >= 0 && next.getY() >= 0 && next.getZ() >= 0)
posivites.add(next);
}
return positives.
}
public ArrayList<Point3D> getNegatives(ArrayList<Point3D> points) {
ArrayList<Point3D> negatives = new ArrayList<>();
for(Point3D next : points) {
if(next.getX() < 0 || next.getY() < 0 || next.getZ() < 0)
negatives.add(next);
}
return negatives.
}
Depending on your scenario it could be wise to have an own container class for the information.
public class PointContainer {
public final Point3D point;
public final int order;
public PointCoordinates (Point3D p, int order) {
this.point = p;
this.order = order;
}
public boolean isNegative() {
return point.getX() < 0 || point.getY() < 0 || point.getZ() < 0;
}
}
and then populate your list with it.
public ArrayList<Point3d> loadFile(String filename) {
ArrayList<PointContainer> words = new ArrayList<PointContainer>();
try {
Scanner chopper = new Scanner(new File(filename));
for (int line = 0; chopper.hasNext(); line ++) {
double x=chopper.nextDouble();
double y=chopper.nextDouble();
double z=chopper.nextDouble();
Point3d p=new Point3d(x, y, z);
PointCoordinates pc = new PointCoordinates(p, line);
words.add(pc);
// just calling nextLine will cause an exception at the end of the file unless you have an blank line there on purpose, so this makes sure it does
}
chopper.close();
} catch (Exception e) {
System.out.println(e);
}
return words;
}
That way you have that information ready to use for everything you want to do.