Snakes and Ladders (Low-Level Design)

Snakes and Ladders (Low-Level Design)

·

4 min read

Problem Definition

Snakes and Ladders is a popular board game enjoyed by people of all ages around the world. The game's objective is to move from the starting point to the finishing point, usually by rolling dice and moving the corresponding number of steps on the board. However, the presence of snakes and ladders on the board adds an element of luck and surprise to the game, making it more exciting to play.

Requirements

  1. Players will set the number of dice used at the start of the game.

  2. Each player will play turn by turn.

  3. More than 2 players should play the game.

  4. The game will end when there are only 2 players left.

  5. The player should reach exactly at last cell or should get a number in dice to reach beyond the last cell to win.

Objects

  1. Board

  2. Cell

  3. Snake

  4. Ladder

  5. Dice

  6. Game

  7. Player

UML Diagram

Code

See on GitHub

@Getter
public class Dice {
    private int diceCount;

    public Dice(int count)
    {
        diceCount= count;
    }

    public int rollDice()
    {
        int count=0, total=0;
        while(count< diceCount)
        {
            total+= ThreadLocalRandom.current().nextInt(1, 7);
            count++;
        }
        return total;
    }
}
@Getter
public class Snake {
    private int start;
    private int end;
    public Snake(int start, int end)
    {
        this.start= start;
        this.end= end;
    }
@Getter
public class Ladder {
    private int start;
    private int end;
    public Ladder(int start, int end)
    {
        this.start = start;
        this.end= end;
    }
}
@Getter
@Setter
public class Cell {
    private Snake snake;
    private Ladder ladder;

    public Cell(){
        snake= null;
        ladder= null;
    }

}
@Getter
public class Player {
    private int id;
    private String name;
    @Setter
    private int currentPosition;

    public Player(int id, String name){
        this.id= id;
        this.name= name;
        currentPosition= 1;
    }

}
@Getter
public class Board {
    private int boardSize;
    private int noOfSnake;
    private int noOfLadder;
    @Setter
    private Cell[][] cell= new Cell[1000][1000];

    public Board(int size, int snake, int ladder){
        boardSize= size;
        noOfSnake= snake;
        noOfLadder= ladder;

        initializeBoard();
    }

    private void initializeBoard()
    {
        for(int i=1; i<=boardSize; i++)
        {
            cell[generateRowNo(i)][generateColNo(i)]= new Cell();
        }
        generateSnakes();
        generateLadders();
    }
    private void generateSnakes()
    {
        int snakeCount=0;
        while(snakeCount< noOfSnake)
        {
            int start= ThreadLocalRandom.current().nextInt(2, boardSize);
            int end= ThreadLocalRandom.current().nextInt(2, boardSize);
            if(start<=end)
                continue;
            if(cell[generateRowNo(start)][generateColNo(start)].getSnake()==null)
            {
                cell[generateRowNo(start)][generateColNo(start)].setSnake(new Snake(start, end));
                snakeCount++;
            }

        }
    }
    private void generateLadders()
    {
        int ladderCount=0;
        while(ladderCount< getNoOfLadder())
        {
            int start= ThreadLocalRandom.current().nextInt(2, getBoardSize());
            int end= ThreadLocalRandom.current().nextInt(2, getBoardSize());
            if(start>=end)
                continue;
            if(cell[generateRowNo(start)][generateColNo(start)].getLadder()==null &&
                cell[generateRowNo(start)][generateColNo(start)].getSnake()==null)
            {
                cell[generateRowNo(start)][generateColNo(start)].setLadder(new Ladder(start, end));
                ladderCount++;
            }

        }
    }
    private int generateRowNo(int num)
    {
        int row= (int) (num-1/Math.sqrt(getBoardSize()));
        return row;
    }
    private int generateColNo(int num)
    {
        int col= (int) (num-1%Math.sqrt(getBoardSize()));
        return col;
    }
    public int getFinalPosition(int position)
    {
        int row= generateRowNo(position);
        int col= generateColNo(position);
        int finalPosition= position;
        if(cell[row][col].getSnake()!=null)
        {
            System.out.println("Snake bit at: " + position);
            finalPosition= cell[row][col].getSnake().getEnd();


        }
        else if (cell[row][col].getLadder()!=null)
        {
            System.out.println("Climbed ladder at: " + position);
            finalPosition= cell[row][col].getLadder().getEnd();

        }


        return finalPosition;
    }


}
@Getter
@Setter
public class Game {
    private Queue<Player> players= new ArrayDeque<Player>();
    private Board board;
    private Dice dice;

    public void addPlayers(int id, String name)
    {
        Player player= new Player(id, name);
        players.add(player);
        System.out.println("Player added: "+ name);
    }
    public void setBoard(int size, int snake, int ladder)
    {
        board= new Board(size, snake, ladder);
        System.out.println("Board set of size: "+ size);
        System.out.println("Snakes added:" + snake);
        System.out.println("Ladders added: "+ ladder);
    }
    public void setDice(int count)
    {
        dice= new Dice(count);
        System.out.println("No. of dice used: "+ count);
    }
    public void startGame()
    {
        List<String> winners= new ArrayList<>();
        while(players.size()>2)
        {
            Player player= players.poll();
            System.out.println("Turn: " + player.getName());
            System.out.println(player.getName() + " is at : " + player.getCurrentPosition());
            int move= dice.rollDice();
            System.out.println("Dice shows : " + move);
            int currentPosition= player.getCurrentPosition() + move;
            if(currentPosition>=board.getBoardSize())
            {
                winners.add(player.getName());
                System.out.println(player.getName() + " won");
                continue;
            }
            if(currentPosition< board.getBoardSize())
            {
                int finalPosition = board.getFinalPosition(currentPosition);
                player.setCurrentPosition(finalPosition);
                System.out.println(player.getName() + " moved to : " + finalPosition);
            }
            players.add(player);

        }
        System.out.println("Game Over");
        displayResult(winners);
    }
    private void displayResult(List<String> winners)
    {
        System.out.println("Results:");
        int count=0;
        for(String playerName: winners)
        {
            count++;
            System.out.println("Rank " + count + ": " + playerName);

        }
    }
}
public class SnakeLadderApplication {
    public static void main(String args[])
    {
        Game game= new Game();
        game.setDice(2);
        game.setBoard(100, 4, 3);
        game.addPlayers(1, "Swati");
        game.addPlayers(2, "Shristi");
        game.addPlayers(3, "Shivani");
        game.addPlayers(4, "Sonal");
        game.startGame();
    }
}

In this blog post, we have explored the technical aspects of implementing Snake and Ladder, including board layout, movement rules, and gameplay mechanics. We have discussed how to represent the game state using data structures, and examined the algorithms for handling player movement, snake bites, and ladder climbs.