Solved

How to undo a move played on a board game

Posted on 2011-09-26
8
77 Views
Last Modified: 2015-09-23
Hi Experts,

This is a kind of follow up question from my previous one(Q_27326449.html)...
I am writing a Connect-4, 6*7 board game.
Every time a player makes a move, I store that move in an instance of the GameStack class that I have written.
I want to be able to allow undo / redo operation by popping from stackA and pushing into stackB, (i.e for undo)  and popping from stackB for redo.

I am getting the following error messages:

[ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]       
[ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]       
[ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]       
[ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]       
[ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]       
[ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]       
A      B      C      D      E      F      G      
player's color: Red
move#: 0
f([ O ]), please type your move:  
e
[ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]       
[ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]       
[ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]       
[ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]       
[ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]       
[ _ ]      [ _ ]      [ _ ]      [ _ ]      [ O ]      [ _ ]      [ _ ]       
A      B      C      D      E      F      G      
player's color: Blue
move#: 1
h([ X ]), please type your move:  
b
[ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]       
[ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]       
[ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]       
[ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]       
[ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]      [ _ ]       
[ _ ]      [ X ]      [ _ ]      [ _ ]      [ O ]      [ _ ]      [ _ ]       
A      B      C      D      E      F      G      
player's color: Red
move#: 2
f([ O ]), please type your move:  
u
Exception in thread "main" java.lang.NullPointerException
      at org.c4.code.GameStack.performPop(GameStack.java:20)
      at org.c4.code.GameModel.undo(GameModel.java:513)
      at org.c4.code.Main.placePieceOnBoard(Main.java:160)
      at org.c4.code.Main.startGame(Main.java:62)
      at org.c4.code.Main.main(Main.java:27)

Pointing at the line :
Point point = (Point) stack.pop;  in the GameStack class.
Is this a good way to approach this at all?
GameStack.java file has been uploaded in the previous mentioned post.
I am not sure if I should resubmit it with this post.
Thanks.
0
Comment
Question by:Smanyx
  • 6
  • 2
8 Comments
 
LVL 47

Accepted Solution

by:
for_yan earned 500 total points
ID: 36597585
Just be simpler - store all your moves in the ArrayList - and you'll be able to undo them one by one very easily
0
 
LVL 47

Expert Comment

by:for_yan
ID: 36597611

What is the point to do it recursively like that?
Sure it will get nullpointer exception

	static Point performPop(Stack stack)
	{
		Point point = (Point)stack.pop();
		try
		{
			performPop(stack);
		}
		catch (EmptyStackException e)
		{
			
		}
		return point;
	}

Open in new window

0
 

Author Comment

by:Smanyx
ID: 36597665
>> Just be simpler - store all your moves in the ArrayList
Thanks, I keep it in mind and will try to do it.

But just for the sake of learning, how would I accomplish the same with stack data-structure?
I have never used a stack before but I thought it could be a good idea to use it here.
And obviously, I am clumsy using it, thus your remark:
>>  What is the point to do it recursively like that?
     Sure it will get nullpointer exception

It's only in trying to use it that I can understand the best way to work with it. Talking about Stack.
I projected that the question would allow me to understand lots, thus the 500pts assigned to it.
I realize  that I don't know and I want to learn...
Thanks.
0
 
LVL 47

Expert Comment

by:for_yan
ID: 36597730


I'd thisn you do something like that:

if(!stack.empty()) stack.pop();
else
System.out.println("no more moves to undo!");

Although I'm not sure how would you do it with the stack.

If you have all your moves in ArrayList - you can esili gothrough this array list and draw your current position of elements.
You ca easily write such method.
So when you want to undo you remove las element and call this method to draw your positions again
Very simple and convenient



0
DevOps Toolchain Recommendations

Read this Gartner Research Note and discover how your IT organization can automate and optimize DevOps processes using a toolchain architecture.

 
LVL 47

Expert Comment

by:for_yan
ID: 36597890
You can also use LinkedList instead of ArrayList - this collection has even method removeLast()

0
 

Author Comment

by:Smanyx
ID: 36598595
Whether I use an ArrayList or a LinkedList, should I save the move as a point-coordinates, right!?
Because, I can do something like, arrayList.add(pRow, pCol) but when I want to use it ...

 >> If you have all your moves in ArrayList - you can esili gothrough this array list and draw your current position of elements.
I am a bit confused here, 'coz if I draw from the ArrayList, this structure only contains the moves made, I still need to draw the board with empty space where no move has been played...

Looking at my printBoard() method:

public static void printBoard()
      {
            int currentColumn = 1;
            
            for (int mRow = (GameModel.BOARD_HEIGHT); mRow > 0; mRow--)
            {
                  /*
                   * printing the leading row number
                   */
//                  if (mRow < (GameModel.BOARD_HEIGHT + 1))
//                  {
////                        System.out.print((mRow - 1) + ". ");
//                        System.out.print((mRow - 1));
//                  }

                  for (int mCol = 0; mCol < (GameModel.BOARD_WIDTH); mCol++)
                  {
                        int [][] board = game.getBoard();
                        
                        if (mRow != GameModel.BOARD_WIDTH)
                        {
                              System.out.print(convertBoard(board[mRow - 1][mCol]) + "\t");
                        }
                  }
                  System.out.println(" ");
            }
            
            // print each column name
            for (int i = 0; i < (GameModel.BOARD_WIDTH + 1); i++)
            {
                  switch(currentColumn)
                  {
                        case 1:
                              System.out.print('A' + "\t");
                              break;
                        case 2:
                              System.out.print('B' + "\t");
                              break;
                        case 3:
                              System.out.print('C' + "\t");
                              break;
                        case 4:
                              System.out.print('D' + "\t");
                              break;
                        case 5:
                              System.out.print('E' + "\t");
                              break;
                        case 6:
                              System.out.print('F' + "\t");
                              break;
                        case 7:
                              System.out.print('G' + "\t");
                              break;
                  }
                  currentColumn++;
            }
            System.out.println("");
            int x = game.getCurrentPlayer();
            //String playerColor = "";
            switch(x)
            {
                  case 0:
                        playerColor = "Red";
                        break;
                  case 1:
                        playerColor = "Blue";
                        break;
            
            }
            
            System.out.println("player's color: " + playerColor);
            System.out.println("move#: " + game.getMoveNumber());
          System.out.println(returnPlayerName() + "(" + convertBoard(game.getCurrentPlayer()) + ")" + ", please type your move:  ");
      }

Could you lead me to a better understanding of how to implement this all undo/redo thing? Especially how to redraw the screen after undo and/or redo? I am thinking of using two ArrayLists one for undo and the other for redo. Am I on the right track?
0
 
LVL 47

Expert Comment

by:for_yan
ID: 36598991
No you don't need two arraylists.
Just one which will have all the moves in the order they were made. The empty screen is always drawn the same way - you don't need to keep any additional information to draw it. So you make a sepratae method - which will first draw empty table and then add aLl the moves, exactly as you did before when the play was happening with the difference that you don't need to stop and ask the user for the next move, but rather take the move from the ArrayList . Yuoi pro baby don't need to test if it was a win in between also.
Also keep in mind that you can't keep juist two strings as one element of arraylist - you should have one objeect as each element - say yoir Point obect would be OK. Your poicture is the function of a sequence of moves - so you don't need two arrayLists at leat for undo option. If you want to be able to do redo, then you may want to keep temporary list if tgose which you removed to pull them out of it for redo. Another option will be kust to maintain the instance variabe - thre number okf moves to draw. This number would be equaal to number of moves and to zise of your arraylist b y default , but when you make uindo - you'l reduce this number by one for each undo, when youmake redio - just increase this numb er by one. So once you hjave this numbeer as a oparrameter of the method which redraws youur picture - that would be fine. Then you can also have option redoAll - the you'll set this parameter to the size of oiur arraylist
0
 
LVL 47

Expert Comment

by:for_yan
ID: 36599331
If I were you, I'd rather make this the basic methid of your application. This method will take two parameters - arraylist which contains moves as they were entered by the user (arrayList of Strings as user entered them - you have one letter strings as I understand) and the integer value which normall would be less than equal to the size of the arraylist. And in the body of this method - you'll traverse the list up to the elemnt specified by the integer - and process the moves the way you process them now.
Given the fact that on the board 6 by 7 the speed is not essential - you can use this method even in your normal play operations - just add tghe each move of the user to the arraylist,incvrease the integer - in normal play the intger will be always equal to the arraylist size - and replay all moves. It will be a little bit slower, than to handle last move onlyu - but no one can notice it on the 6 by 7 board.
And when you need undo-redo - it will be just a matter of chjanging this controlling integer.
Well, any of these designswith arraylist  would be fine. Of course if you move to some huige tables and long winning rows then time will become a factor and you don't want to replay all the moves all the time.
 
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Are you developing a Java application and want to create Excel Spreadsheets? You have come to the right place, this article will describe how you can create Excel Spreadsheets from a Java Application. For the purposes of this article, I will be u…
In this post we will learn how to connect and configure Android Device (Smartphone etc.) with Android Studio. After that we will run a simple Hello World Program.
Viewers will learn one way to get user input in Java. Introduce the Scanner object: Declare the variable that stores the user input: An example prompting the user for input: Methods you need to invoke in order to properly get  user input:
This tutorial explains how to use the VisualVM tool for the Java platform application. This video goes into detail on the Threads, Sampler, and Profiler tabs.

863 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

22 Experts available now in Live!

Get 1:1 Help Now