?
Solved

How to undo a move played on a board game

Posted on 2011-09-26
8
Medium Priority
?
151 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 6
  • 2
8 Comments
 
LVL 47

Accepted Solution

by:
for_yan earned 1500 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
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
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
 
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

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

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

By the end of 1980s, object oriented programming using languages like C++, Simula69 and ObjectPascal gained momentum. It looked like programmers finally found the perfect language. C++ successfully combined the object oriented principles of Simula w…
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
Viewers learn about the third conditional statement “else if” and use it in an example program. Then additional information about conditional statements is provided, covering the topic thoroughly. Viewers learn about the third conditional statement …
Viewers will learn about basic arrays, how to declare them, and how to use them. Introduction and definition: Declare an array and cover the syntax of declaring them: Initialize every index in the created array: Example/Features of a basic arr…
Suggested Courses

649 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