Shifting history in command-pattern with undo/redo? - java

I'm having a problem concerning a command pattern with undo/redo function. The simple problem is, when my history is full, I want to remove the least recently used command from the history and add the new one on execute.
I got this code snippet from my professor:
public class CommandHistory implements CommandInterface{
private static final int MAX_COMMANDS = 2;
private Command[] history = new Command[MAX_COMMANDS];
private int current = -1;
#Override
public void execute(Command command) {
current++;
if (current == MAX_COMMANDS){ // if full, then shift
for (int i = 0; i < MAX_COMMANDS - 1; i++){
history[i] = history[i+1];
}
}
history[current] = command;
history[current].execute();
}
In really doubt the if-clause is incorrect, because the current command index remains 2 and only command at index 0 is shifted to 1. But he says this is the way to go. What am I missing?

The loop itself is fine, but two problems:
You're quite correct that when current == MAX_COMMANDS is true and you do the loop, current is incorrect and needs adjusting.
From a maintenance perspective, current == MAX_COMMANDS is the wrong comparison, it should be current == history.length. (Otherwise, it's easy to change the initialization of history to use something other than MAX_COMMANDS but forget to change every check like current == MAX_COMMANDS.)
I would check current before incrementing it, and only increment it if you're not shifting the contents down:
public void execute(Command command) {
if (current == history.length - 1){ // if full, then shift
for (int i = 0; i < history.length - 1; i++) {
history[i] = history[i+1];
}
} else {
current++;
}
history[current] = command;
history[current].execute();
}

Related

How to Make Program flow control jump back to a former loop in java?

So I have written a code that allows a user to find a word in a TextArea. I have nearly succeeded but for one thing. here, I will show you all the code and tell my problem.
if(ta.getText().length() != 0 && t1.getText().length() != 0)
{
char c1[] = ta.getText().trim().toCharArray();
char c2[] = t1.getText().trim().toCharArray();
for(int i=startFlag;i<c1.length;i++)
{
if(c1[i]==c2[0])
{
start = i;
break;
}
}
k=start;
for(int i=0;i<c2.length;i++)
{
if(c2[i] != c1[start++])
{
}
else
countFlag++;
}
if(countFlag==c2.length)
{
ta.select(k,c2.length);
startFlag++;
}
}
For reference, ta is the TextArea and t1 is the TextField where the user enters a word to find. i have a problem in the second for loop. What should I write in the if () block there so that whenever c2[i] != c1[start++] the control is shifted to the first for loop, that would again determine the value of start?
Create a method to get "start" that you can then call whenever you want.
if(ta.getText().length() != 0 && t1.getText().length() != 0)
{
char c1[] = ta.getText().trim().toCharArray();
char c2[] = t1.getText().trim().toCharArray();
k=getStart(startFlag, c1.length);
for(int i=0;i<c2.length;i++)
{
if(c2[i] != c1[start++])
{
start = getStart(startFlag, c1.length);
}
else
countFlag++;
}
if(countFlag==c2.length)
{
ta.select(k,c2.length);
startFlag++;
}
}
And getStart() is:
public int getStart(int startFlag, int length) {
for(int i=startFlag;i<length;i++)
{
if(c1[i]==c2[0])
{
return i;
}
}
}
You may need different inputs to getStart(), but hopefully this gets across the general idea.
The way your code is set up right now, what you're asking for is impossible. To do what you're asking, you'll need to refactor your current code into different methods. More specifically, you'll need to put the for loops into their own methods and then call these methods.
So what you would need to do is make a separate method for the for loop.
public static int startForLoop(int i) {
for(int i=startFlag;i<c1.length;i++)
{
if(c1[i]==c2[0])
{
start = i;
break;
}
}
}
Then you can just call startForLoop(0) initially and in the 2nd for loops if statment:
if(c2[i] != c1[start++])
{
startForLoop(start+1)
}
This will continue the for loop where it left off. If you need to run the 2nd for loop again then you have to make a separate method for it as well and basically place both of them in a while loop that continues till you find the result you want in the 2nd for loop.
May be this code piece help you what you are looking for.
Basically it moves along with the string to be searched in keeping in mind the index of the string to be searched for.
Sorry but i have implemented it in java, but the notion is same and the result returned is the best what i got.you must give it a try!
private static String searchString(String searchIN,String searchFOR){
if (searchFOR != "") {
int index = searchIN.toUpperCase().indexOf(searchFOR.toUpperCase());
String before = "";
String highlighted = "";
String after = "";
while (index >= 0) {
int len = searchFOR.length();
before = searchIN.substring(0, index);
highlighted = "\"" + searchFOR + "\"";//do what ever you want to do with searched string
after = searchIN.substring(index + len);
searchIN = before + highlighted + after;
index = searchIN.toUpperCase().indexOf(searchFOR.toUpperCase(), index + highlighted.length());
}
}
return searchIN;
}

There are two functions with the same structure, but different details. How to get rid of duplication?

So, here is my functions:
private void sendLeft() {
leftSendersIndexes = newLeftSendersIndexes;
Agent rightRecepient;
int rightRecepientIdx = 0;
Agent leftSender;
for (int i = 0; i < leftSendersIndexes.size(); i++) {
rightRecepientIdx = leftSendersIndexes.get(i) + 1;
rightRecepient = list.get(rightRecepientIdx);
leftSender = list.get(rightRecepientIdx - 1);
rightRecepient.setNewLeftMsg(leftSender.getLeftMsg());
rightRecepient.setLeftMsg(0); // reset left messages
}
}
private void sendRight() {
rightSendersIndexes = newRightSendersIndexes;
Agent leftRecepient;
int leftRecepientIdx = 0;
Agent rightSender;
for (int i = 0; i < rightSendersIndexes.size(); i++) {
leftRecepientIdx = rightSendersIndexes.get(i) - 1;
leftRecepient = list.get(leftRecepientIdx);
rightSender = list.get(leftRecepientIdx + 1);
leftRecepient.setNewRightMsg(rightSender.getRightMsg());
}
}
They are very similar. The problem is that in first function I have leftRecepientIdx+1 and after that leftRecepientIdx-1 and I have leftRecepientIdx-1 and leftRecepientIdx+1 in second function. I may to combine two functions in one and add a boolean parameter. But is there a better way to get rid of duplication?
One way to do that is with this refactoring:
private void sendLeft() {
leftSendersIndexes = newLeftSendersIndexes;
send(leftSendersIndexes, -1);
}
private void sendRight() {
rightSendersIndexes = newRightSendersIndexes;
send(rightSendersIndexes, +1);
}
private void send(List<Integer> indexes, int direction) {
for (int i = 0; i < indexes.size(); i++) {
int recipientIdx = indexes.get(i) - direction;
Agent recipient = list.get(recipientIdx);
Agent sender = list.get(recipientIdx + direction);
if (direction == -1) {
recipient.setNewLeftMsg(sender.getLeftMsg());
recipient.setLeftMsg(0); // reset left messages
}
else {
recipient.setNewRightMsg(sender.getRightMsg());
}
}
}
The send method encapsulates the logic based on the direction parameter: +1 for right, -1 for left.
The order in which those appears is important, I would suggest merging, but, I have no idea what that would do. Keep them separate, if this was borrowed, this was made on purpose.
Both functions are some send functions where sender and receiver are different and reset may happen. So I would try to make one function with arguments sender, receiver and boolean reset.

remove(int index) LinkedList Self-Implementation

I am trying to learn performance of LinkedList in comparison to ArrayList
I have made my removal method as follows
Data In the LinkedList, which is being removed is about 1million elements.
My Problem, After Removing All Items: This is the Time Recd.
If I Use Java LinkedList remove(int index) Time: 2000 nanoseconds
If I Use my Custom remove(int index) Time: 34407000 nanoseconds
Could someone please look at my code and tell me where I am going wrong. I am actually suppose to remove the data by index positions, since the comparison I am trying to attain are by index positions for ArrayList.
public Object remove(int index)
{
checkElementIndex(index);
return unlink(getNode(index));
}
private Object unlink(ListNode node)
{
final Object element = node.item;
final ListNode next = node.next;
final ListNode prev = node.prev;
if (prev == null)
{
first = next;
} else
{
prev.next = next;
node.prev = null;
}
if (next == null)
{
last = prev;
} else
{
next.prev = prev;
node.next = null;
}
node.item = null;
size--;
return element;
}
private ListNode getNode(int index)
{
if (index < (size >> 1))
{
ListNode node = first;
for (int i = 0; i < index; i++)
{
node = node.next;
}
return node;
} else
{
ListNode node = last;
for (int i = size - 1; i > index; i--)
{
node = node.prev;
}
return node;
}
}
private void checkElementIndex(int index)
{
if (index < 0 || index >= size)
{
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
}
}
// BOTH THE LIST CONTAIN 1million items.
startTime = System.nanoTime();
for (int i = linkedList.size()-1; i >= 0; i--)
{
linkedList.remove(i);
}
endTime = System.nanoTime();
duration = endTime - startTime;
System.out.println("LinkedList Removal Time: " + duration);
// This is the Java Collection LinkedList
startTime = System.nanoTime();
for (int i = linkedList.size()-1; i >= 0; i--)
{
javaLinkedList.remove(i);
}
endTime = System.nanoTime();
duration = endTime - startTime;
System.out.println("My Removal Time: " + duration);
I appreciate, each and every possible suggestion. Thank you.
(continued from comments)
No problem! First step is to download a profiler (I use VisualVM. There are other ones out there, but unfortunately I'm not familiar with them...) Once that's downloaded, go ahead fire that up.
The next step is figuring out how to attach the profiler to your process. Once you start up VisualVM, you should see a list of running Java programs on the right. You can ignore that for now. The trick is that you'll need a long-running program to have enough time to attach the profiler to the process. For something like your code, an easier way would be to use Scanner.nextLine() to block the program in between loops, sort of like this:
Scanner scanner = new Scanner(System.in);
scanner.nextLine(); // This stops the program and waits for user input.
// This will give us all the time in the world to attach the profiler.
// Your code
for (int i = linkedList.size()-1; i >= 0; i--)
{
linkedList.remove(i);
}
scanner.nextLine(); // Same thing here
for (int i = linkedList.size()-1; i >= 0; i--)
{
javaLinkedList.remove(i);
}
Now, go ahead start your program. If you go back to VisualVM, you should be able to see your program!
Now double-click on your program. You should see a few messages appear in the console in your program, and the view in VisualVM should change. Go to the "Sampler" tab, click "CPU", then go back to your program and hit enter.
What you see should be pretty self-explanatory. On the left are fully qualified method names with package + class, and a bar representing the portion of CPU time that methods use. Use that to identify where your program is spending all its time. And there you go! If you need more time to profile, just add more elements to the linked lists.
Just a word of caution though; profiling can be deceiving, because if another method is messing up your linked list structure it can make a perfectly good method work far harder than it has to. For example, I had to implement HashMap as part of a school assignment. When I profiled I noticed that the code to look in buckets was taking up 97%+ of CPU time, even though there was nothing wrong with it. Turns out that a test to get a proper bucket had >> instead of <<, turning the HashMap into a LinkedList instead! So while profiling is a good start (and usually is the only thing you need to do to identify problems), just keep in mind that the errors could be elsewhere.
I hope that this helped!

Depth-first search terminating early

I'm creating a program in Java that solves the n-puzzle, without using heuristics, simply just with depth-first and breadth-first searches of the state space. I'm struggling a little bit with my implementation of depth-first search. Sometimes it will solve the given puzzle, but other times it seems to give up early.
Here's my DFS class. DepthFirstSearch() is passed a PuzzleBoard, which is initially generated by shuffling a solved board (to ensure that the board is in a solvable state).
public class DepthFirst {
static HashSet<PuzzleBoard> usedStates = new HashSet<PuzzleBoard>();
public static void DepthFirstSearch(PuzzleBoard currentBoard)
{
// If the current state is the goal, stop.
if (PuzzleSolver.isGoal(currentBoard)) {
System.out.println("Solved!");
System.exit(0);
}
// If we haven't encountered the state before,
// attempt to find a solution from that point.
if (!usedStates.contains(currentBoard)) {
usedStates.add(currentBoard);
PuzzleSolver.print(currentBoard);
if (PuzzleSolver.blankCoordinates(currentBoard)[1] != 0) {
System.out.println("Moving left");
DepthFirstSearch(PuzzleSolver.moveLeft(currentBoard));
}
if (PuzzleSolver.blankCoordinates(currentBoard)[0] != PuzzleSolver.n-1) {
System.out.println("Moving down");
DepthFirstSearch(PuzzleSolver.moveDown(currentBoard));
}
if (PuzzleSolver.blankCoordinates(currentBoard)[1] != PuzzleSolver.n-1) {
System.out.println("Moving right");
DepthFirstSearch(PuzzleSolver.moveRight(currentBoard));
}
if (PuzzleSolver.blankCoordinates(currentBoard)[0] != 0) {
System.out.println("Moving up");
DepthFirstSearch(PuzzleSolver.moveUp(currentBoard));
}
return;
} else {
// Move up a level in the recursive calls
return;
}
}
}
I can assert that my moveUp(), moveLeft(), moveRight(), and moveDown() methods and logic work correctly, so the problem must lie somewhere else.
Here's my PuzzleBoard object class with the hashCode and equals methods:
static class PuzzleBoard {
short[][] state;
/**
* Default constructor for a board of size n
* #param n Size of the board
*/
public PuzzleBoard(short n) {
state = PuzzleSolver.getGoalState(n);
}
public PuzzleBoard(short n, short[][] initialState) {
state = initialState;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Arrays.deepHashCode(state);
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
PuzzleBoard other = (PuzzleBoard) obj;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (state[i][j] != other.state[i][j])
return false;
}
}
return true;
}
}
As previously stated, sometimes the search works properly and finds a path to the solution, but other times it stops before it finds a solution and before it runs out of memory.
Here is a snippet of the output, beginning a few moves before the search stops searching.
...
Moving down
6 1 3
5 8 2
0 7 4
Moving right
6 1 3
5 8 2
7 0 4
Moving left
Moving right
Moving up
6 1 3
5 0 2
7 8 4
Moving left
Moving down
Moving right
Moving up
Moving up
Moving right
Moving down
Moving up
Moving down
Moving up
Moving down
Moving up
Moving down
Moving up
Moving down
...
I truncated it early for brevity, but it ends up just moving up and down dozens of times and never hits the solved state.
Can anyone shed light on what I'm doing wrong?
Edit: Here is MoveUp(). The rest of the move methods are implemented in the same way.
/**
* Move the blank space up
* #return The new state of the board after the move
*/
static PuzzleBoard moveUp(PuzzleBoard currentState) {
short[][] newState = currentState.state;
short col = blankCoordinates(currentState)[0];
short row = blankCoordinates(currentState)[1];
short targetCol = col;
short targetRow = row;
newState[targetCol][targetRow] = currentState.state[col - 1][row];
newState[targetCol - 1][targetRow] = 0;
return new PuzzleBoard(n, newState);
}
I have had many problems with hashset in the past best thing to try is not to store object in hashset but try to encode your object into string.
Here is a way to do it:-
StringBuffer encode(PuzzleBoard b) {
StringBuffer buff = new StringBuffer();
for(int i=0;i<b.n;i++) {
for(int j=0;j<b.n;j++) {
// "," is used as separator
buff.append(","+b.state[i][j]);
}
}
return buff;
}
Make two changes in the code:-
if(!usedStates.contains(encode(currentBoard))) {
usedStates.add(encode(currentBoard));
......
}
Note:- Here no need to write your own hashcode function & also no need to implement equals function as java has done it for you in StringBuffer.
I got one of the problems in your implementation:-
In th following code:-
static PuzzleBoard moveUp(PuzzleBoard currentState) {
short[][] newState = currentState.state;
short col = blankCoordinates(currentState)[0];
short row = blankCoordinates(currentState)[1];
short targetCol = col;
short targetRow = row;
newState[targetCol][targetRow] = currentState.state[col - 1][row];
newState[targetCol - 1][targetRow] = 0;
return new PuzzleBoard(n, newState);
}
Here you are using the reference of same array as newState from currentState.state so when you make changes to newState your currentState.state will also change which will affect DFS when the call returns. To prevent that you should initialize a new array. Heres what to be done:-
static PuzzleBoard moveUp(PuzzleBoard currentState) {
short[][] newState = new short[n][n];
short col = blankCoordinates(currentState)[0];
short row = blankCoordinates(currentState)[1];
short targetCol = col;
short targetRow = row;
for(int i=0;i<n;i++) {
for(int j=0;j<n;j++) {
newState[i][j] = currentState.state[i][j];
}
}
newState[targetCol][targetRow] = currentState.state[col - 1][row];
newState[targetCol - 1][targetRow] = 0;
return new PuzzleBoard(n, newState);
}
Do this change for all moveup,movedown....
Moreover I donot think your hashset is working properly because if it was then you would always find your new state in hashset and your program would stop. As in equals you comparing the state arrays with same reference hence will always get true. Please try and use my encode function as hash.

Java Sorting "queue" list based on DateTime and Z Position (part of school project)

For a school project i have a list of 50k containers that arrive on a boat.
These containers need to be sorted in a list in such a way that the earliest departure DateTimes are at the top and the containers above those above them.
This list then gets used for a crane that picks them up in order.
I started out with 2 Collection.sort() methods:
1st one to get them in the right X>Y>Z order
Collections.sort(containers, new Comparator<ContainerData>()
{
#Override
public int compare(ContainerData contData1, ContainerData contData2)
{
return positionSort(contData1.getLocation(),contData2.getLocation());
}
});
Then another one to reorder the dates while keeping the position in mind:
Collections.sort(containers, new Comparator<ContainerData>()
{
#Override
public int compare(ContainerData contData1, ContainerData contData2)
{
int c = contData1.getLeaveDateTimeFrom().compareTo(contData2.getLeaveDateTimeFrom());
int p = positionSort2(contData1.getLocation(), contData2.getLocation());
if(p != 0)
c = p;
return c;
}
});
But i never got this method to work..
What i got working now is rather quick and dirty and takes a long time to process (50seconds for all 50k):
First a sort on DateTime:
Collections.sort(containers, new Comparator<ContainerData>()
{
#Override
public int compare(ContainerData contData1, ContainerData contData2)
{
return contData1.getLeaveDateTimeFrom().compareTo(contData2.getLeaveDateTimeFrom());
}
});
Then a correction function that bumps top containers up:
containers = stackCorrection(containers);
private static List<ContainerData> stackCorrection(List<ContainerData> sortedContainerList)
{
for(int i = 0; i < sortedContainerList.size(); i++)
{
ContainerData current = sortedContainerList.get(i);
// 5 = Max Stack (0 index)
if(current.getLocation().getZ() < 5)
{ //Loop through possible containers above current
for(int j = 5; j > current.getLocation().getZ(); --j)
{ //Search for container above
for(int k = i + 1; k < sortedContainerList.size(); ++k)
if(sortedContainerList.get(k).getLocation().getX() == current.getLocation().getX())
{
if(sortedContainerList.get(k).getLocation().getY() == current.getLocation().getY())
{
if(sortedContainerList.get(k).getLocation().getZ() == j)
{ //Found -> move container above current
sortedContainerList.add(i, sortedContainerList.remove(k));
k = sortedContainerList.size();
i++;
}
}
}
}
}
}
return sortedContainerList;
}
I would like to implement this in a better/faster way. So any hints are appreciated. :)
I think you probably want to sort with a single Comparator that compares on all of the criteria. E.g.:
compareTo(other)
positionComparison = this.position.compareTo(other.position)
if positionComparison != 0
return positionComparison
return this.departureTime.compareTo(other.departureTime)

Categories