Java Hash table linear probing - java

Hi I am having issues printing and/or adding entries to my hash table I am looking to handle collisions with linear probing. Could someone help me? This is NOT a school project or assignment, just for fun.
I am new to the Java programming language.
I cannot get all of the entries to output to the console and I am wondering where I am going wrong.
/**
* File : ContactTable.java
* Project : None
* Programmer : Braiden Gole
* First version : 2020-05-20
* Description : This is the implementation of a hash table algorithm. We will be
* storing a record with three pieces of information for contacting
* a customer that is: First name, last name, email.
*/
import java.util.ArrayList;
import java.util.Scanner;
import java.util.InputMismatchException;
class ContactTable {
/** -- Class header comment
* Name : HashNode
* Purpose : This represents an entry in our hash table.
*/
static class HashNode {
String firstName;
String lastName;
String emailAddress;
int position;
HashNode next;
}
/** -- Class header comment
* Name : TableMapper
* Purpose : This class represents the operations that our hash table will be
* able to carry out.
*/
static class TableMapper {
private ArrayList<HashNode> hashTable = new ArrayList<>();
private final int KTABLELIMIT = 5;
/** -- Method header comment
* Method : initializeContactTable
* Description : This will add (null) markers so we can detect when a position
* has been filled with an entry or not.
* Parameters : None
* Returns : None
*/
private void initializeContactTable() {
for (int positions = 0; positions < KTABLELIMIT; positions++) {
hashTable.add(null);
}
}
/** -- Method header comment
* Method : hashMethod
* Description : This is the hash method to calculate the position at which the
* record of contact will sit in the contact table. We will be
* using the name field to store the record.
* Parameters : key
* Returns : hashValue % KTABLELIMIT
*/
private int hashMethod(String key) {
int hashValue = 0;
for (int letters = 0; letters < key.length(); letters++) {
hashValue += key.charAt(letters);
}
return hashValue % KTABLELIMIT;
}
/** -- Method header commment
* Method : insertRecord
* Description : This method will insert the entire object record into the
* has table. We will handle collisions with linear probing and
* make use of the "wrap around method."
* Parameters : key, position lastName, email
* Returns : currentSize
*/
private int insertRecord(String key, int position, String lastName, String email) {
HashNode checkPosition = hashTable.get(position);
HashNode newRecord = new HashNode();
// Check to make sure that the name does not already exist.
while (checkPosition != null) {
if ((checkPosition.firstName.equals(key)) == true) { return 1; }
checkPosition = checkPosition.next;
}
// The calculated position has been moved, recalculate.
checkPosition = hashTable.get(position);
if (checkPosition == null) {
newRecord.firstName = key;
newRecord.position = position;
newRecord.lastName = lastName;
newRecord.emailAddress = email;
newRecord.next = checkPosition;
hashTable.add(position, newRecord);
return 0;
} else {
while ((hashTable.get(position)) != null) {
++position;
position %= KTABLELIMIT;
}
newRecord.firstName = key;
newRecord.position = position;
newRecord.lastName = lastName;
newRecord.emailAddress = email;
newRecord.next = hashTable.get(position);
hashTable.add(position, newRecord);
return 0;
}
}
/** -- Method header comment
* Method : showContacts
* Description : This will display all contact records to the console.
* Parameters : None
* Returns : None
*/
private void showContacts() {
for (int entries = 0; entries < KTABLELIMIT; entries++) {
if ((hashTable.get(entries)) != null) {
System.out.println();
System.out.println(hashTable.get(entries).firstName);
System.out.println(hashTable.get(entries).lastName);
System.out.println(hashTable.get(entries).emailAddress);
}
}
}
}
public static void main(String[] args) {
TableMapper mapper = new TableMapper();
Scanner reader = new Scanner(System.in);
// The primaryKey is the users first name.
String primaryKey = "";
String lastName = "";
String email = "";
int index = 0;
int currentSize = 0;
int returnInsertVal = 0;
// Initialize the contact table with (null) markers.
mapper.initializeContactTable();
boolean contactEntryCondition = true;
while (contactEntryCondition) {
System.out.println();
System.out.print("Enter in your first name: ");
primaryKey = reader.next();
System.out.print("Enter in your last name: ");
lastName = reader.next();
System.out.print("Enter in your email address: ");
email = reader.next();
// Calculate the index at which the record will sit.
index = mapper.hashMethod(primaryKey);
// Use the calculated index to insert the record at the proper position.
returnInsertVal = mapper.insertRecord(primaryKey, index, lastName, email);
// When the table is full exit the loop and print the table.
if (currentSize == mapper.KTABLELIMIT) { contactEntryCondition = false; }
if (returnInsertVal == 0) { ++currentSize; }
else { primaryKey = ""; }
System.out.println(currentSize);
}
reader.close();
// Output the contact records.
mapper.showContacts();
}
}

after each hashTable.add(position, newRecord) your underlying list (hashTable) grows in size by one
void add(int index, E element)
Inserts the specified element at the specified position in this list (optional > operation). Shifts the element currently at that position (if any) and any subsequent elements to the right (adds one to their indices).
this messes up the "bookkeeping" that you do on the table.
in showContacts(), change the for line as follows:
for (int entries = 0; entries < hashTable.size(); entries++) {
and it will print all the elements inside the table.
you should rethink your implementation and use a "fixed size underlying list" (possibly an array) enlarging it only when it's necessary and rehashing when you do so.

Related

Error on: Binary search tree on java with text file

Here's a program that will accept a text file (.txt, not Microsoft word or pdf stuff, just a basic text file) as a COMMAND LINE ARGUMENT and store each word (accepting ALL punctuation as if it were a space character, including apostrophe's) in a binary tree. Each node in the tree stores an ArrayList which holds the number of times that word occurs(first element) and each position in the text file that it occurs (all following elements). The user is shown the total number of words, and you can search for a word to see how many times and where in the file it is stored.
The code is not mine the autor is MasudKhan, i'm learning with it how to do my own code for a similar program.
I have been having some trouble finding the error with this code and why it's not working, the error message is:
"Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
at A3Driver.main(A3Driver.java:10)"
A3Driver.java
/**
Assignment3
This class is a driver for a program which reads in a file,
whose name is given as a command line argument, and stores each
word as well as how many occurences of that word and the positions of
each occurence in the text file. The program then offers to allow
the user to search for any input word and produce the info for it,
if any.
*/
import java.io.*;
import java.util.*;
public class A3Driver
{
/**
main method for Binary word search program.
*/
public static void main(String[] args)
{
WordBST newTestWordBST = new WordBST(new File(args[0]));
System.out.println("Total number of words in file: " +
WordBST.wordPosition);
System.out.println("Number of unique words in file: " +
WordBST.uniqueWordCount);
System.out.print("Most used word: " + WordBST.mostUsedWord);
System.out.println(", times used: " + WordBST.highestCount);
System.out.println("\n\n");
Scanner keyboard = new Scanner(System.in);
String input = "";
while(!input.equals("n"))
{
System.out.print("Search for word (y/n)? ");
input = keyboard.nextLine();
if(input.toLowerCase().equals("y"))
{
System.out.print("Enter word: ");
newTestWordBST.searchBinaryTree(keyboard.nextLine());
}
}
System.out.println("Thank you, goodbye.");
/**
To output all tree info, uncomment this section.
newTestWordBST.inOrderTraverse();
*/
}
}
WordBST.java
/**
Assignment3
This class holds a Binary search tree of WordBSTNodes.
*/
import java.io.*;
import java.util.*;
public class WordBST
{
WordBSTNode root;
static int wordPosition, uniqueWordCount = 0, highestCount;
static String mostUsedWord;
/**
Constructor: initializes the root to null.
*/
public WordBST()
{
root = null;
}
/**
Constructor: initializes root to parameter value.
#param theRoot the root of this WordBST object
*/
public WordBST(WordBSTNode theRoot)
{
root = theRoot;
}
/**
Constructor: initializes root to hold nodes containing the words and
data from the parameter file.
#param text the input file containing words
*/
public WordBST(File text)
{
try
{
BufferedReader bR = new BufferedReader(new FileReader(text));
root = readBinaryTree(bR);
}
catch(IOException e)
{
System.out.println("Error reading file. Exiting.");
System.exit(1);
}
}
/**
Wrapper method for the recursive add method.
#param item the item to add to the BST
*/
public void add(String item)
{
root = add(root, item);
}
/**
Postcondition: uses recursion to add item to the BST node in the
appropriate position, or add information to the matching node.
#param localRoot the local node being checked in the current call
#param item the item to add to the BST
*/
private WordBSTNode add(WordBSTNode localRoot, String item)
{
if(localRoot == null) // item not in tree - add it
{
uniqueWordCount++; // total distinct word count
ArrayList<Integer> temp = new ArrayList<Integer>();
temp.add(1);
temp.add(wordPosition);
return new WordBSTNode(item, temp);
}
else if(item.compareTo(localRoot.word) == 0) // item == localRootData
{
localRoot.countAndPos.set(0, localRoot.countAndPos.get(0) + 1);
localRoot.countAndPos.add(wordPosition);
if(localRoot.countAndPos.get(0) > highestCount)
{
highestCount = localRoot.countAndPos.get(0);
mostUsedWord = localRoot.word;
}
return localRoot;
}
else if(item.compareTo(localRoot.word) < 0) //item < localRootData
{
localRoot.leftTree = add(localRoot.leftTree, item);
return localRoot;
}
else // item > localRootData
{
localRoot.rightTree = add(localRoot.rightTree, item);
return localRoot;
}
}
/**
Postcondition: performs an inorder traversal.
*/
public void inOrderTraverse()
{
inOrderTraverse(root);
}
/**
Perform an inorder traversal.
#param localRoot the current node being traversed
*/
private void inOrderTraverse(WordBSTNode localRoot)
{
if(localRoot.leftTree != null) // left
{
inOrderTraverse(localRoot.leftTree);
}
// middle
//output current root
System.out.print(localRoot.word);
for(int i = 0; i < localRoot.countAndPos.size(); i++)
{
System.out.print(", " + localRoot.countAndPos.get(i));
}
System.out.println();
if(localRoot.rightTree != null) // right
{
inOrderTraverse(localRoot.rightTree);
}
}
/**
Wrapper method for searchBinaryTree recursive method.
#param searchWord the String word to search for
*/
public void searchBinaryTree(String searchWord)
{
searchBinaryTree(searchWord, root);
}
/**
Postcondition: if word is found in the search, it is output along with
occurrence information, and if it is not found, not-found info is output.
#param searchWord the word to search for
#param localRoot the localRoot being checked in the current call
*/
public void searchBinaryTree(String searchWord, WordBSTNode localRoot)
{
if( (searchWord.compareTo(localRoot.word) < 0) &&
(localRoot.leftTree != null) )
{
searchBinaryTree(searchWord, localRoot.leftTree);
}
else if( (searchWord.compareTo(localRoot.word) > 0) &&
(localRoot.rightTree != null) )
{
searchBinaryTree(searchWord, localRoot.rightTree);
}
else if(searchWord.compareTo(localRoot.word) == 0)
{
System.out.println("Position number(s) of occurence(s):");
for(int i = 1; i < localRoot.countAndPos.size(); i++)
{
System.out.println("word #" + localRoot.countAndPos.get(i));
}
System.out.println("Word found.");
System.out.println("Occurences: " +
localRoot.countAndPos.get(0));
}
else
{
System.out.println("Word does not exist.");
}
}
/**
#param bR the bufferedReader to read from
#return returns a node containing the info from the file which the input
BufferedReader is reading from
*/
public WordBSTNode readBinaryTree(BufferedReader bR)
{
String data = "";
String temp;
try
{
while(bR.ready())
{
data = data.concat(bR.readLine().toLowerCase() + "\n");
}
if(data == "")
{
return null;
}
}
catch(IOException e)
{
System.out.println("Error reading file. Exiting.");
System.exit(1);
}
return readBinaryTree(
new StringTokenizer(data,
" \t\n\r\f.,!`'-\"\\:()[]{}=+_*&^%$##?<>;|/~"));
}
/**
#param inputST the StringTokenizer to repeatedly add words from
#return returns a node containing the info from the file which the input
BufferedReader is reading from
*/
public WordBSTNode readBinaryTree(StringTokenizer inputST)
{
wordPosition = 1;
ArrayList<Integer> tempArrayList =
new ArrayList<Integer>(wordPosition++);
tempArrayList.add(1);
WordBST tempBST = new WordBST(
new WordBSTNode(inputST.nextToken(), tempArrayList));
highestCount = 1;
mostUsedWord = tempBST.root.word;
while(inputST.hasMoreTokens())
{
tempBST.add(inputST.nextToken());
wordPosition++; // current position, and total words in file
}
return tempBST.root;
}
}
WordBSTNode.java
/**
Assignment3
This class holds a node for a binary search tree. The node includes
a pointer to it's left subtree and it's right subtree, as well as String
data, and an ArrayList containing the number of occurences of the
data in the user's input file in the first position, followed by the
word number in each following position.
*/
import java.util.*;
public class WordBSTNode
{
WordBSTNode leftTree;
WordBSTNode rightTree;
String word;
ArrayList<Integer> countAndPos;
/**
Constructor: no arg constructor must never be used to avoid
confusion between a null node element and a null element content.
*/
public WordBSTNode()
{
System.out.println("Cannot creat empty node, sorry.");
}
/**
Constructor: initializes parent, word, and countAndPos instance
variables.
#param theWord the word to be stored in this node
#param theCountAndPos an ArrayList containing this node's word's
count and position's
*/
public WordBSTNode(String theWord, ArrayList<Integer> theCountAndPos)
{
leftTree = null;
rightTree = null;
word = theWord;
countAndPos = theCountAndPos;
}
}
Any help is really apreciated.

iterating over list containing objects of another class

I am studying Java and I have an assignment to do. Here are the requirements.
There are two classes
Runner
MarathonAdmin
We have to create a runners list which holds the instances of Runner class
and have to assign values to instances name, age and agegroup taken from another txt file.
In another part there is requirement that create random numbers between 90 to 180 inclusive and iterate over each runner and assign random number value to runner's time instance.
I am stuck in last part. I am not getting how to iterate over each runner in runners list. I am including code I have done so far.
I need help with runMarathon() method whose requirement states
Write a public method for the MarathonAdmin class called runMarathon() that takes no arguments and returns no value. The method should iterate over runners, and for each runner generate a random number between 90 and 180 (inclusive) which should be used to set the time (in minutes) for that runner.
import java.util.*;
import java.io.*;
import ou.*;
import java.util.Random;
/**
* Write a description of class MarathonAdmin here.
*
* #author (your name)
* #version (a version number or a date)
*/
public class MarathonAdmin
{
// instance variables - replace the example below with your own
private List<Runner> runners;
private String ageGroup;
private String age;
private Random randomNumber;
private String result;
String ageRunner;
String ageGrouprunners;
Scanner lineScanner;
int ans;
Runner runnerobj = new Runner();
/**
* Constructor for objects of class MarathonAdmin
*/
public MarathonAdmin()
{
// initialise instance variables
runners = new ArrayList<>();
}
/**
* An example of a method - replace this comment with your own
*
* #param y a sample parameter for a method
* #return the sum of x and y
*/
public void readInRunners()
{
String pathName = OUFileChooser.getFilename();
File aFile = new File(pathName);
String nameRunner;
BufferedReader bufferedFileReader = null;
try
{
bufferedFileReader = new BufferedReader(new FileReader(aFile));
String currentLine = bufferedFileReader.readLine();
while ( currentLine != null)
{
lineScanner = new Scanner(currentLine);
lineScanner.useDelimiter(",");
nameRunner = lineScanner.next();
ageRunner = lineScanner.next();
ageGrouprunners = result;
int size = runners.size();
if (Integer.parseInt(ageRunner) < 18)
{
result = "junior";
System.out.println(currentLine +" category" + " : Junior");
}
if (Integer.parseInt(ageRunner) > 55)
{
result = "senior";
System.out.println(currentLine +" category"+ " : Senior");
}
if (Integer.parseInt(ageRunner) > 18 && Integer.parseInt(ageRunner) < 55)
{
result = "standard";
System.out.println(currentLine +" category"+ " : Standard");
}
Runner runnerobj = new Runner();
runnerobj.setName(nameRunner);
runnerobj.setAgeGroup(ageGrouprunners);
System.out.println(runnerobj); //rough test
runners.add(runnerobj);
currentLine = bufferedFileReader.readLine();
}
}
catch (Exception anException)
{
System.out.println("Error: " + anException);
}
finally
{
try
{
bufferedFileReader.close();
}
catch (Exception anException)
{
System.out.println("Error: " + anException);
}
}
}
public void runMarathon()
{
int size = runners.size();
for ( int runnersIndex = 0; runnersIndex <= size; runnersIndex ++ )
{
this.randomNumber = new Random();
ans = randomNumber.nextInt(190 - 80 +1 ) + 90 ;
System.out.println(ans);
String runnerTime;
for( String nameRunner :)
{
}
}
}
}
Your call to .nextInt() is not going to give you the range you expect because the calculation is wrong. You also don't need to do a calculation - just provide the upper bound.
The way you've set up your loop with the runnersIdx, all you need to do is access the runner with the index. See the documentation for List since that's what you used (List<Runner>).
Whenever you're learning a programming language, you'll want to bookmark the documentation website and reference it frequently. The docs for java 7 are here: http://docs.oracle.com/javase/7/docs/api/
You may also find the Java Tutorials to be helpful.
Your loop in runMarathon() function. You'll want to retrieve each runner from your List and assign a time.
for ( int runnersIndex = 0; runnersIndex <= size; runnersIndex ++ ) {
this.randomNumber = new Random();
ans = randomNumber.nextInt(190 - 80 +1 ) + 90 ;
Runner runner = runners.get(runnersIndex);
runner.setTime(ans); //make sure you create the getters/setters for this value
}

How do I loop into the ArrayList's Block's Tuple?

I am sorry if the code is long.
Block and Tuple are self defined classes. Their attributes are protected. Block contains a ArrayList of Tuples. Tuple has attribute int Key and String value
I have ArrayList[] bucketLstS and Block[] bucketBlocksS
ArrayList[] bucketLstS = new ArrayList[Setting.memorySize - 1];
Block[] bucketBlocksS = new Block[Setting.memorySize - 1];
for (int i = 0; i < bucketBlocksS.length; i++) {
bucketLstS[i] = new ArrayList<Tuple>();
bucketBlocksS[i] = new Block();
}
//Get individual relS keys
RelationLoader sLoader = relS.getRelationLoader();
while (sLoader.hasNext()) {
Block[] blocks = sLoader.loadNextBlocks(1);
for (Block b : blocks) {
numIO++;
if (b != null) {
for (Tuple t : b.tupleLst) {
//Hash the key to determine which Bucket
bucketIdx = t.key % (Setting.memorySize - 2);
//System.out.println(bucketBlocksS[bucketIdx].getNumTuples());
//check if the block is already full
if (bucketBlocksS[bucketIdx].getNumTuples() >= Setting.blockFactor) {
bucketLstS[bucketIdx].add(bucketBlocksS[bucketIdx]);
bucketBlocksS[bucketIdx] = new Block();
blkNum++;
}
bucketBlocksS[bucketIdx].insertTuple(t);
}
}
}
}//end while
The question is that I need to loop into each Block, so that I can access each Tuple's Key and value I tried this:
for (int i = 0; i < bucketLstS.length; i++) {
System.out.println(i + " " + bucketLstS[i]);
for (int j = 0; j < bucketLstS[i].size(); j++) {
//Access a Block in Block Array
System.out.println(j + " " + bucketLstS[i].get(j));
}
}
But then I am stuck. The output is like:
0 [project2.Block#558fee4f, project2.Block#5c66b06b, project2.Block#59c87031, project2.Block#763dcf03, project2.Block#53e20a9a, project2.Block#1d262f7c, project2.Block#35f784d7, project2.Block#d325aef, project2.Block#64f007ad]
0 project2.Block#558fee4f
1 project2.Block#5c66b06b
2 project2.Block#59c87031
3 project2.Block#763dcf03
4 project2.Block#53e20a9a
5 project2.Block#1d262f7c
6 project2.Block#35f784d7
7 project2.Block#d325aef
8 project2.Block#64f007ad
But how to I get into the Tuple of a Block to get to the key?
(To obtain key, can use Tuple.key)
Following is the Class for Block
import java.util.ArrayList;
public class Block {
/**
* List of tuples contained in this block
*/
protected ArrayList<Tuple> tupleLst;
public Block(){
this.tupleLst=new ArrayList<Tuple>(Setting.blockFactor);
}
/**
* Insert a tuple t to this block
* #param t is a tuple to be inserted to this block
* #return true if tuple t is successfully inserted into this block and false if the block is full
*/
//One tupleLst can store up to "10" tuples
public boolean insertTuple(Tuple t){
if(tupleLst.size()<Setting.blockFactor){
tupleLst.add(t);
return true;
}
return false;
}
/**
* #return number of tuples stored in this block
*/
public int getNumTuples(){
return tupleLst.size();
}
/**
* Print this block
* #param printTuple is a flag to indicate whether the details of the tuples are printed
*/
public void print(boolean printTuple){
System.out.println("[BlockSize: "+getNumTuples()+"]");
if(printTuple){
for(Tuple t:tupleLst){
System.out.println(t);
}
}
}

algorithm to find the largest area

................................
.XXXXXXXXXXXXXXX.....XXXXXXXXXX.
.X.....X.......X.....X........X.
.X.....X.......XXXXXXX........X.
.XXXXXXXXXXXX.................X.
.X....X.....X.................X.
.X....X.....XXXX..............X.
.XXXXXX........X..............X.
......X........X..............X.
......X........X..............X.
......X........X..............X.
......XXXXXXXXXXXXXXXXXXXXXXXXX.
................................
Looking for an algorithm to find the largest area. Here, "area" is defined as a number of dots (.) bounded by Xs.
private static void readFile(File inputFile) throws IOException {
Scanner fileScanner = new Scanner(inputFile);
Point previousPoint = null;
int rowCount = 0;
while(fileScanner.hasNext()){
String line = fileScanner.next();
String[] points = line.split(" ");
for(int columnCount=0;columnCount<points.length;columnCount++){
if(points[columnCount].equalsIgnoreCase("x")){
Point currentPoint = new Point();
currentPoint.setxValue(columnCount);
currentPoint.setyValue(rowCount);
}
}
rowCount++;
}
}
This is my first and struggling to move further.
This algorithm should work. You just need to implement it in Java.
Load the file into a char[][]. (1 char[] per line)
Loop through the char[][] (2 dimensionally)
upon finding a '.', perform flood fill, changing all '.' to ',', also incrementing a counter on every change.
At the end of flood fill, compare this counter with a globally set maximum. If it's higher, then set it as the new highest. (If the edges are not a proper boundary, then do not set this counter if you reached an edge during flood fill by setting a flag during 3)
Return the highest you set.
If you have any specific problems with the Java implementation, then let me know
Geobits:
Note: If you want to exclude the area "outside" any boxes, flood as
usual, but discard any area that hits the edge during the fill(skip
step 2.2 for that flood).
When doing the flood fill, you have 2 types of boundaries. A wall ('X'), and the edge of the array(which you need to explicitly check for to avoid OutOfBounds exceptions). If you hit an out of bounds, keep doing the fill, but set a flag so you know later to not consider the number you counted for the biggest box.
I was given this as assignment in an interview process and this is the compile and running code
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class FindArea {
public static void main(String[] args)
{
String fileName="C:\\map.txt";
FindArea area = new FindArea();
try{
FileReader inputFile = new FileReader(fileName);
BufferedReader bufferReader = new BufferedReader(inputFile);
char[][] twoArray= new char[100][100];
String line;
int i=0;
while ((line = bufferReader.readLine()) != null) {
twoArray[i] = line.toCharArray();
System.out.println(line);
i++;
}
bufferReader.close();
System.out.println("file read");
System.out.println("Max area: " + area.getMaxArea(twoArray));
} catch(Exception e) {
System.out.println("error : " + e.getMessage());
}
}
/**
* Get the maximum area from the given map
*
* #param charArray
* #return
*/
private int getMaxArea(char[][] charArray) {
HashMap<Integer, ArrayList<String>> numberOfBoxes = convertToBoxes(charArray);
numberOfBoxes = mergeOverlapAreas(numberOfBoxes);
int largeSize = 0;
for (Integer key : numberOfBoxes.keySet()) {
ArrayList<String> list = numberOfBoxes.get(key);
System.out.println("Key : " + key + " Size : " + list.size());
if (largeSize < list.size()) {
largeSize = list.size();
}
}
return largeSize;
}
/**
* Convert the 2d Array to HashMap
* Key being the count of boxes and
* Value being the list of indexes associations
*
* #param charArray
* #return
*/
private HashMap<Integer, ArrayList<String>> convertToBoxes(char[][] charArray) {
HashMap<Integer, ArrayList<String>> numberOfBoxes = new HashMap<Integer, ArrayList<String>>();
int boxes = 0;
for(int i=1; i<charArray.length; i++) {
for (int j=0; j<charArray[i].length; j++) {
if (charArray[i][j] == '.') {
boolean isExists = false;
for(Integer key : numberOfBoxes.keySet()) {
ArrayList<String> arrList = numberOfBoxes.get(key);
if(arrList != null) {
if(arrList.contains((i-1) + "-" + j) ||
arrList.contains(i + "-" + (j-1))) {
isExists = true;
arrList.add(i + "-" + j);
numberOfBoxes.put(key, arrList);
}
}
}
if (!isExists) {
ArrayList<String> list = new ArrayList<String>();
list.add(i + "-" + j);
numberOfBoxes.put(boxes, list);
boxes++;
}
}
}
}
return numberOfBoxes;
}
/**
* Check for the points exists in more than one area
* #param numberOfBoxes
* #return
*/
private HashMap<Integer, ArrayList<String>> mergeOverlapAreas( HashMap<Integer, ArrayList<String>> numberOfBoxes) {
for(Integer key : numberOfBoxes.keySet()) {
ArrayList<String> list1 = numberOfBoxes.get(key);
for (Integer key2 : numberOfBoxes.keySet()) {
if (key < key2) {
ArrayList<String> list2 = numberOfBoxes.get(key2);
Iterator<String> listIter = list2.iterator();
while(listIter.hasNext()) {
if (list1.contains(listIter.next())) {
list1.addAll(list2);
Set<String> noDuplicates = new HashSet<String>(list1);
numberOfBoxes.put(key, new ArrayList<String>(noDuplicates));
break;
}
}
}
}
}
return numberOfBoxes;
}
}
Here's an algorithm that's an alternative to flood fill. This method sweeps through the 2d array and whenever you encounter a node(pixel) that's outside to the left (right, top, bottom), it flags the current node as outside, ie if your neighbour is 'outside', you're marked 'outside' too.
The algorithm continues like this until there're no more updates. That means that all the nodes that are reachable from the 'outside' have been flagged. BTW, this is a very similar problem to level sets functions and updating them (where flood fill is also used). The nice this about this method is that it is ideal for parallelization.
1. Load 2D Symbol Array from File
2. hasupdates = false
3. Create 'isinside' bool array -> {
if(symbolarray[row][col] == '.' and row or col is at boundary)
isinside[row][col] = false
else
isinside[row][col] = true
}
4. do{
Do a sweep from left to right (for all rows) -> //This loop can be run parallely on all rows.
If (!isinside[row][col-1] and symbolarray[row][col] == '.'){
isinside[row][col] = false //mark current value as 'outside'
hasupdates = true
}
Do similar sweeps from right to left, top to bottom(all columns) and bottom to top.
}while(hasupdates)
5. Go through 'isinside' array and count the number of falses.
If you have huge files where you have to do this area calculation, you can have the sweeps along the rows and columns run parallely, because each row update (column update) is independent of the other updates.

Sudoku game serialization issue

I am creating the Sudoku game and I am trying to provide options to save, save as, and open games. I am using JFileChooser to do this. I am able to save (or "save as") but when I try to open a saved file, I get an error. I am new to programming and I'm hoping someone could spot the issue and educate me on how to read in the contents of the Sudoku board when I am saving (as well as how to deal with re-creating the Sudoku board when I open the file). I hear there is an easier way to deal with this using InputStream/OutputStream instead of Reader/Writer...
Here is my code for the inner class that implements this (I don't know if there's a way to post my entire class without exceeding the character limit for this text box.):
EDIT:
// this inner class provides a JMenuBar object at the top of
// the board
class MenuAtTop extends JMenuBar implements ActionListener{
// SudokuMain object we are dealing with
private SudokuMain main;
// the "File" menu
private JMenu fileMenu;
// the "New Game" option
private JMenuItem newGame;
// the "Open" option
private JMenuItem open;
// the "Save" option
private JMenuItem save;
// the "Save As" option
private JMenuItem saveAs;
// the "Reset" option
private JMenuItem reset;
// the "Quit" option
private JMenuItem quit;
// the ability to choose files
private JFileChooser choose;
// the saved file
// // compiler would not allow "static" keyword
private File fileSaved = null;
private Object opener;
// JDialog object to create a dialog box to prompt
// user for new game information
private JDialog createNewWin;
/**
* Constructs MenuAtTop object.
*
* #param m The SudokuMain object to be referred to.
*/
public MenuAtTop(final SudokuMain m) {
main = m;
opener = null;
choose = new JFileChooser();
// instantiate and bind to reference
fileMenu = new JMenu("File");
add(fileMenu);
// instantiate and bind to reference
newGame = new JMenuItem("New Game");
newGame.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N,
ActionEvent.CTRL_MASK));
fileMenu.add(newGame);
newGame.addActionListener(this);
open = new JMenuItem("Open");
open.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O,
ActionEvent.CTRL_MASK));
fileMenu.add(open);
// add action listener to "Open" option
open.addActionListener(this);
save = new JMenuItem("Save");
save.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S,
ActionEvent.CTRL_MASK));
fileMenu.add(save);
// add action listener to "Save" option
save.addActionListener(this);
saveAs = new JMenuItem("Save As");
saveAs.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A,
ActionEvent.CTRL_MASK));
fileMenu.add(saveAs);
// add action listener to "Save As" option
saveAs.addActionListener(this);
reset = new JMenuItem("Reset");
reset.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R,
ActionEvent.CTRL_MASK));
fileMenu.add(reset);
// add action listener to "Reset" option
reset.addActionListener(this);
quit = new JMenuItem("Quit");
quit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
ActionEvent.CTRL_MASK));
fileMenu.add(quit);
// add action listener to "Quit" option
quit.addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
if(e.getSource().equals(newGame)) {
setEnabled(false);
// create dialog box prompting for the new board information
createNewWin = new Dialog1(main, "Create New Board", true);
// make it visible
createNewWin.setVisible(true);
fileSaved = null;
} else if(e.getSource().equals(open)) {
int returnVal = choose.showOpenDialog(main.win);
if(returnVal == JFileChooser.APPROVE_OPTION) {
boolean error = false;
File openFile = choose.getSelectedFile();
try {
FileInputStream fis = new FileInputStream(openFile);
ObjectInputStream ois = new ObjectInputStream(fis);
opener = ois.readObject();
SudokuBase sudoku = (SudokuBoard) opener;
ois.close();
} catch (Exception exc) {
exc.printStackTrace();
JOptionPane.showMessageDialog(main.win, "Error opening file.");
error = true;
}
// "opener" reads something and it is of type SudokuBase
if(opener != null && opener instanceof SudokuBase){
main.north.remove(main.rowColRegStates);
main.west.remove(main.symbols);
main.east.remove(main.view);
main.view = new SudokuView((SudokuBase) opener);
main.rowColRegStates = new ShowStates(main.view);
main.symbols = new SetSymbols(main.view);
main.north.add(main.rowColRegStates);
main.west.add(main.symbols);
main.east.add(main.view);
main.win.requestFocus();
fileSaved = openFile;
} else {
if(error) {
JOptionPane.showMessageDialog(main.win, "Incorrect file type.");
}
}
}
} else if(e.getSource().equals(save)) {
if(fileSaved == null) {
saveAsPrompt();
} else {
try {
FileOutputStream fos = new FileOutputStream(fileSaved);
ObjectOutputStream oos = new ObjectOutputStream(fos);
board.writeToStream(fos);
oos.writeObject(board);
oos.close();
} catch (Exception exc) {
JOptionPane.showMessageDialog(main.win, "Error saving file.");
}
}
} else if(e.getSource().equals(saveAs)) {
saveAsPrompt();
} else if(e.getSource().equals(reset)) {
int n = JOptionPane.showConfirmDialog(main.win,
"Any player values will" +
" be lost. Proceed?",
"Warning!", 2);
if(n == JOptionPane.OK_OPTION) {
main.board.reset();
main.view.repaint();
}
} else if(e.getSource().equals(quit)) {
closePrompt();
}
}
// This method prompts the user to choose a file to save to,
// and then saves the file.
private int saveAsPrompt() {
boolean saveError;
int rtn = choose.showSaveDialog(main.win);
if(rtn == JFileChooser.APPROVE_OPTION) {
saveError = false;
File fileSaveAs = choose.getSelectedFile();
try {
board.writeToStream(new FileOutputStream(fileSaveAs));
} catch (Exception e) {
JOptionPane.showMessageDialog(main.win, "Error saving file.");
saveError = true;
}
if(!saveError) {
fileSaved = fileSaveAs;
}
}
return rtn;
}
// This method prompts the user whether they want to save before
// closing, only if changes occurred.
private void closePrompt() {
if(true) {
int n = JOptionPane.showConfirmDialog(main.win, "Save game?");
if(n == JOptionPane.YES_OPTION) {
int saved = saveAsPrompt();
if(saved != JFileChooser.CANCEL_OPTION){
main.win.dispose();
}
} else if(n == JOptionPane.NO_OPTION) {
main.win.dispose();
}
}
else { // no changes were made
main.win.dispose();
}
}
}
Here's the class that holds the data (it is extended by SudokuBoard):
// Allow short name access to following classes
import java.util.Observable;
import java.io.InputStream;
import java.io.OutputStream;
public abstract class SudokuBase extends Observable {
// rows per region
private int rows;
// columns per region
private int columns;
// size of a region (rows * columns)
private int size;
// array of each element of entire sudoku board
private int[] grid;
// the masked 8-bit "given" value constant
private static final int GIVEN_MASK = 0x00000100;
// the bitwise complement of the masked "given" constant,
// which produces an unmasked constant
private static final int GIVEN_UNMASK = ~ GIVEN_MASK;
/**
* Enumerated type to store constants that indicate the "State" of
* a specified row, column, or region.
*/
public enum State {COMPLETE, INCOMPLETE, ERROR};
/**
* Constructs SudokuBase object.
*
* #param layoutRows The number of rows per region.
* #param layoutColumns The number of columns per region.
*/
public SudokuBase(int layoutRows, int layoutColumns) {
rows = layoutRows;
columns = layoutColumns;
size = columns * rows;
grid = new int[size*size];
}
/**
* Gets the number of rows per region.
*
* #return The rows per region.
*/
public int getRowsPerRegion() {
return rows;
}
/**
* Gets the number of columns per region.
*
* #return The columns per region.
*/
public int getColumnsPerRegion() {
return columns;
}
/**
* Gets the size of the region (rows * columns).
*
* #return The size of the region.
*/
public int getBoardSize() {
return size;
}
// gets the index of the specified row and column for the grid
private int getIndex(int row, int col) {
// handle invalid arguments
if(row < 0 || row >= size || col < 0 || col >= size) {
String msg = "Error in location";
throw new IllegalArgumentException(msg);
}
return row * size + col;
}
/**
* Gets the value of the element at the specified row
* and column on the grid.
*
* #param row The specified row.
* #param col The specified column.
* #return The value of the element at the specified row and column.
*/
public int getValue(int row, int col) {
return grid[getIndex(row, col)] & GIVEN_UNMASK;
}
/**
* Sets the desired value at the specified row and column.
*
* #param row The specified row.
* #param col The specified column.
* #param value The specified value to be set.
*/
public void setValue(int row, int col, int value) {
// handle invalid argument
if(value < 0 || value > size) {
String msg = "Value out of range: " + value;
throw new IllegalArgumentException(msg);
}
// handle attempt to set a value for a "given" location
if(isGiven(row, col)) {
String msg = "Cannot set given location: " + row + ", " + col;
throw new IllegalStateException(msg);
}
grid[getIndex(row, col)] = value;
setChanged();
notifyObservers();
}
/**
* This method checks the status of the "givens" bit.
*
* #param row The specified row.
* #param col The specified column.
* #return Whether or not the specified location is a "given" value.
*/
public boolean isGiven(int row, int col) {
return (grid[getIndex(row, col)] & GIVEN_MASK) == GIVEN_MASK;
}
/**
* This method sets non-zero values on the Sudoku board with the
* "givens" bit.
*/
public void fixGivens() {
for(int i = 0; i < grid.length; i++)
if(grid[i] != 0)
grid[i] |= GIVEN_MASK;
setChanged();
notifyObservers();
}
/**
* This abstract method gets the "State" (COMPLETE, INCOMPLETE,
* or ERROR) of the specified row.
*
* #param n The specified row.
* #return The "State" of the row.
*/
public abstract State getRowState(int n);
/**
* This abstract method gets the "State" (COMPLETE, INCOMPLETE,
* or ERROR) of the specified column.
*
* #param n The specified column.
* #return The "State" of the column.
*/
public abstract State getColumnState(int n);
/**
* This abstract method gets the "State" (COMPLETE, INCOMPLETE,
* or ERROR) of the specified region.
*
* #param n The specified region.
* #return The "State" of the region.
*/
public abstract State getRegionState(int n);
/**
* Represents the Sudoku board as a grid of appropriate characters.
*
* #return The string representation of the Sudoku board.
*/
public String toString() {
String board = "";
for(int i = 0; i < size; i ++) {
for(int j = 0; j < size; j ++)
board += charFor(i, j) + " ";
board += "\n";
}
return board;
}
// this method provides a character for all possible values encountered on the
// Sudoku board, to be utilized in "toString()"
private String charFor(int i, int j) {
int v = getValue(i, j);
// negative value (invalid)
if(v < 0) {
return "?";
} else if(v == 0) { // blank or zero value
return ".";
} else if(v < 36) { // value from 1 to (size * size)
return Character.toString(Character.forDigit(v, 36)).toUpperCase();
} else { // non-numeric input or v >= size * size (both invalid)
return "?";
}
}
/**
* This method reads from an input stream.
*
* #param is The input stream to read from.
*/
protected void readFromStream(InputStream is) {
}
/**
* This method writes to an output stream.
*
* #param os The output stream to write to.
*/
protected void writeToStream(OutputStream os) {
try {
ObjectOutputStream oos = new ObjectOutputStream(os);
oos.close();
} catch(IOException e) {
}
}
/**
* Gets the "raw" value directly, not having checked whether there is an
* unfixed error message.
*
* #param row The row where the raw value is located.
* #param col The column where the raw value is located.
* #return The raw value.
*/
protected int getRawValue(int row, int col) {
return grid[getIndex(row, col)];
}
/**
* Sets the raw value directly, not having checked whether there is an
* unfixed error message.
*
* #param row The row where the raw value is to be located.
* #param col The column where the raw value is to be located.
*/
protected void setRawValue(int row, int col, int value) {
grid[getIndex(row, col)] = value;
}
protected void reset() {
for(int row = 0; row < rows; row++) {
for(int col = 0; col < columns; col++) {
if(!isGiven(row, col)) {
grid[getIndex(row, col)] = 0;
}
}
}
}
}
Well I cannot give a full answer and I do not want to browse the full source code. But a few pointers for you to find some solution:
Never catch Exceptions like that while developing an application:
} catch (Exception e) {
JOptionPane.showMessageDialog(main.win, "Error saving file.");
saveError = true;
}
With this, you completely loose the chance to detect errors. At least add the following line to your exception handling:
e.printStackTrace();
Normally you would log the exception and so on, but with that you see the source of your error at the console. Better than nothing.
To your more specific problem:
You seem to write an Object to a file holding all the configuration. In your read method something goes wrong. Probably you do not read the same object as you write or something like that. Hard to say without any code. Try to get the exception stack trace and figure out what the problem is. If you cannot figure it out, edit your question with more specific information and I will try to give better directions.
EDIT:
Here is a small example showing serialization of objects for a Sudoku like game:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
public class SerializationExample {
public static void main(String args[]) throws IOException, ClassNotFoundException {
final File target = new File(System.getProperty("java.io.tmp"), "mySerializedObject.txt");
Map<Integer, Integer> initialState = new HashMap<Integer, Integer>();
initialState.put(1, 1);
initialState.put(21, 3);
// ...
GameState state = new GameState(10, initialState);
state.setField(2, 2);
state.setField(3, 8);
System.out.println("Game state before writing to file: " + state);
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(target));
out.writeObject(state);
out.close();
ObjectInputStream in = new ObjectInputStream(new FileInputStream(target));
Object gameStateReadFromFile = in.readObject();
GameState readGameState = (GameState)gameStateReadFromFile;
System.out.println("Read from file: " + readGameState);
}
private static class GameState implements Serializable {
private int[] fields;
private int boardSize;
private int[] fixedFields;
public GameState(int boardSize, Map<Integer, Integer> initialState) {
this.boardSize = boardSize;
this.fields = new int[boardSize * boardSize];
this.fixedFields = new int[this.fields.length];
for (Entry<Integer, Integer> entry : initialState.entrySet()) {
this.fixedFields[entry.getKey()] = entry.getValue();
}
}
public void setField(int index, int value) {
this.fields[index] = value;
}
#Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("\nFixed fields: ");
appendArray(builder, this.fixedFields);
builder.append("\nSet fields: ");
appendArray(builder, this.fields);
return builder.toString();
}
private void appendArray(StringBuilder builder, int[] fieldArray) {
for (int i = 0; i < fieldArray.length; ++i) {
if (fieldArray[i] != 0) {
builder.append("row ").append(i / this.boardSize).append(" column ").append(i % this.boardSize)
.append(" has value ")
.append(fieldArray[i]).append(",");
}
}
}
}
}

Categories

Resources