Monday, May 25, 2020

Design Pattern - Design and Implement Snake and Ladders Game

Design and Implement Snake and Ladders Game 

I will write the code and tell you the thought process of how one should proceed in Design and implement the code. Snake and Ladder show how various objects like a game board, snack, ladders, etc come together to produce a program. Snack and ladder game is a very famous interview question to check your design pattern concept. I think we all know about the Snack and Ladder Game how we play it So I will jump to design pattern.

In the Snake and Ladder game, there are some objects that will need to be created like below:
  • GameBoard
  • PlayerPiece
  • BoardSquare
  • Snake
  • Ladder
  • Die
And one more thing we need an object of the game itself. the main design decisions we have to take based on their responsibilities of Objects.

So Die should be rolled this is the Die object responsibility. What about BoardSquare or even the Game itself? So we could keep track of which piece is on which square using the BoardSquare or even the game itself. What about PlayerPiece?It should have a useful role in the application like it will be responsible for knowing which BoardSquare it currently occupies. There is an association between PlayerPiece and BoardSquare.

This is just one way of designing the solution. Just give a thought about the Snake and Ladder classes?
Why because they are very similar in fact could be modeled as a single class that links two squares together whether they take the player up or down on the board does not really make any difference to the implementation but we will keep them apart.

What do we do about the relationship between the Snack and ladders and the BoardSquares?
A BoardSquare needs to know if it contains the head of a snake or the foot of ladder though it does not need to know if it has the tail of a snake or the head of a ladder because these do not cause the PlyerPiece to move again. We cannot have both a snake and a ladder on any one square.

The main logic:

Finally, the SnakeAndLadders class acts as the program entry point and creates the GameBoard and the PlyerPieces. it has the main method that creates an instance of the class and triggers the play method. This handles the main game loop that iterates until the game is over.

Implementation :

So the Snake and Ladder objects need to be positioned on the board so they can be referenced by the BoardSquare that they are placed on and reference the other BoardSquare that they point to. Now to set a position of a Snake, a parameterized constructor is provided that takes the head of and tail positions as parameters.


Snake(BoardSquare head, BoardSquare tail){
 setTail(tail);
head.addSnake(this);
}

Similarly the Ladder constructor stores the top of the ladder and passes itself back to the BoardSquare that contains its foot.

Ladder(BoardSquare top, BoardSquare foot)
{
   setTop(top);
   foot.addLadder(this)
}

in both the case we omit the public prefix because the class itself is not public.

class Snake
{
  private BoardSquare tail;
  Snake(BoardSquare head,BoardSquare tail)  
  {
    setTail(top);
head.addSnake(this);
  }
  private void setTail(BoardSquare tail)
  {
    this.tail=tail;
  }
  private BoardSquare getTail()
  {
    return tail;
  }
  
  void movePlayerPiece(PlayerPiece counter)
  {
    System.out.println("Down the Snake to " + getTail().getPosition());
counter.setCurrentPostion(getTail());
  }
}

class Ladder
{
  private BoardSquare top;
  Ladder(BoardSquare top,BoardSquare foot)  
  {
    setTail(top);
head.addLadder(this);
  }
  private void setTop(BoardSquare top)
  {
    this.top=top;
  }
  private BoardSquare getTop()
  {
    return top;
  }
  void movePlayerPiece(PlayerPiece counter)
  {
    System.out.println("Up the Ladder to " + getTop().getPosition());
counter.setCurrentPostion(getTop());
  }
}

class PlayerPiece
{
 private BoardSquare currentPosition; 
 private String color;
 PlayerPiece(String color)
 {
   setColor(color);
 }
  private void setColor(String color)
  {
    this.color=color;
  }
  String getColor()()
  {
    return color;
  }
  BoardSquare getCurrentPosition()
  {
    return currentPosition;
  }
  void setCurrentPostion(BoardSquare newPosition)
  {
   currentPosition = newPosition
  }
}

class BoardSquare
{
 private Snake aSnake = null;
 private Ladder aLadder = null;
 private int position;
 BoardSquare(int position)
 {
   setPosition(position);
 }
 int getPosition()
 {
   return position;
 }
 private void setPosition(int position)
 {
  this.position = position;
 }
 void addSnake(Snake s)
 {
   aSnake = s
 }
 public void addLadder(Ladder l)
 {
  aLadder = l;
 }
 private boolean hasSnake()
 {
  return null!=aSnake;
 }
 private boolean hasLadder()
 {
   return null!=aLadder;
 }
 
 public void movePlayerPiece(PlayerPiece counter)
  {
counter.setCurrentPostion(this);
if(hasSnake())
{
  aSnake.movePlayerPiece(counter);
}
if(hasLadder())
{
  aLadder.movePlayerPiece(counter);
}
  }
}



private BoardSquare[] squares;
private Die die;
static final int MAX_SQUARES = 100;
class Gameboard
{
  static final int START_SQUARE =1;
  Gameboard()
  {
    die = new Die();
squares = new BoardSquare[START_SQUARE + MAX_SQUARES];
for(int i=START_SQUARE;i<=MAX_SQUARES;i++)
{
  squares[i]=new BoardSquare[i];
}
  }
  
  // add the Ladders
  new Ladder(squares[38],squares[1]);
  new Ladder(squares[14],squares[4]);
  new Ladder(squares[31],squares[9]);
  new Ladder(squares[42],squares[21]);
  new Ladder(squares[84],squares[28]);
  new Ladder(squares[44],squares[36]);
  new Ladder(squares[67],squares[51]);
  new Ladder(squares[91],squares[71]);
  new Ladder(squares[100],squares[80]);
  
  //add the Snakes
  
  new Snake(squares[16],squares[6]);
  new Snake(squares[47],squares[26]);
  new Snake(squares[49],squares[11]);
  new Snake(squares[56],squares[53]);
  new Snake(squares[62],squares[19]);
  new Snake(squares[64],squares[60]);
  new Snake(squares[87],squares[24]);
  new Snake(squares[93],squares[73]);
  new Snake(squares[95],squares[75]);
  new Snake(squares[98],squares[78]);
  
  // constructor creates the square and adds the 
  
  BoardSquare getStartSquare()
  {
    return square[START_SQUARE];
  }
  
  public void movePlayerPiece(PlayerPiece counter)
  {
BoardSquare current = counter.getCurrentPosition();
int nextPosition = current.getPosition() + die.getRoll();
if(nextPosition > MAX_SQUARES)
{
  System.out.println("you need to land  exactly on the last suquare to win!");
}
else
{
  counter.moveTo(squares[nextPosition]);
}
System.out.println(counter.getColor + "counter on " + counter.getCurrentPosition().getPosition());
  }
}

public class SnakesAndladders
{
  private Gameboard board;
  public SnakesAndladders()
  {
    board = new Gameboard();
  }
  public void play()
  {
    PlayerPiece counter = new PlayerPiece("RED")
counter.setCurrentPostion(board.getStartSquare());
while(counter.getCurrentPosition(),getPosition() < Gameboard.MAX_SQUARES)
{
  board.movePlayerPiece(counter)
}
System.out.println(counter.getColor + "counter finished on  " + counter.getCurrentPosition().getPosition());
  }
  public static void main(String[] args)
  {
     SnakesAndladders myGame = new SnakesAndladders();
myGame.play()
  }
}


Output : 

up the ladder tp 14
RED counter on 14
RED counter on 15
...........................
.............................
.............................
RED counter on 100
RED counter finished on 100