Explore topic-wise InterviewSolutions in .

This section includes InterviewSolutions, each offering curated multiple-choice questions to sharpen your knowledge and support exam preparation. Choose a topic below to get started.

1.

How to design Snake and Ladder?

Answer»

Here is how the "Snake and Ladder problem" can be solved by using the above approach.

1. Gathering Requirements: Create a multiplayer Snake and Ladder game in such a way that the game should take input N from the user at the start of the game to create a board of size N x N. The board should have some snakes and ladders placed randomly in such a way the snake will have its head position at a higher number than the tail and ladder will have start position at smaller number than END position. Also, No ladder and snake create a cycle and no snake tail position has a ladder start position & vice versa.

The players take their turn one after another and during their turn, they roll the dice to get a random number and the player has to move forward that many positions. If the player ends up at a cell with the head of the snake, the player has to be punished and should go down to the cell that CONTAINS the tail of the same snake & If the player ends up at a cell with the start position of a ladder, the player has to be rewarded and should climb the ladder to reach the cell which has a top position of the ladder. Initially, each player is outside of the board (at position 0). If at any point of time, the player has to move outside of the board (say player at position 99 on a 100 cell board and dice rolls give 4) the player stays at the same position.

Possible future extension:

  • The game can be played by more than one dice. (i.e. if there are two dices then the numbers from 2 to 12 will be generated).
  • On getting a 6, you get another turn and on getting 3 consecutive 6s, all three of those get cancelled.

2. Class Diagram & Use Case Diagram:

3. Code IMPLEMENTATION:

Driver.java

package snakeLadder; public class Driver { public static void main(String[] args) { SpecialEntity snake1 = new Snake(12, 28); SpecialEntity snake2 = new Snake(34, 78); SpecialEntity snake3 = new Snake(6, 69); SpecialEntity snake4 = new Snake(65, 84); SpecialEntity ladder1 = new Ladder(24, 56); SpecialEntity ladder2 = new Ladder(43, 83); SpecialEntity ladder3 = new Ladder(3, 31); SpecialEntity ladder4 = new Ladder(72, 91); Board board = new Board(10); board.addSpecialEntity(snake1); board.addSpecialEntity(snake2); board.addSpecialEntity(snake3); board.addSpecialEntity(snake4) board.addSpecialEntity(ladder1); board.addSpecialEntity(ladder2); board.addSpecialEntity(ladder3); board.addSpecialEntity(ladder4); Dice dice = new Dice(6); Game game = new Game(board, dice); Player player1 = new Player("p1"); Player player2 = new Player("P2"); Player player3 = new Player("p3"); players = List<Player>(){player1, player2, player3}; game.addPlayers(players); game.launch(); } }

Game.java

package snakeLadder; import snakeLadder.GameStatus;import snakeLadder.Player;import snakeLadder.Dice;import snakeLadder.Board; import java.util.Queue;import java.util.Scanner;import java.util.LinkedList; public class Game { Board board; Dice dice; Queue<Player> players; GameStatus staus; public Game(Board board, Dice dice) { this.board = board; this.dice = dice; this.players = new LinkedList<Player>(); this.status = GameStatus.NOT_STARTED; } public void startGame() { this.status = GameStatus.RUNNING; board.printBoard(); // Run until we have only 1 player left on the board while(players.size() > 1) { Player player = players.poll(); makeMove(currPlayer); if(player.getPosition() == board.getTotalCells()) System.out.println(player.getName() + " has completed the game!"); else players.add(player); } this.status = GameStatus.FINISHED; } private void makeMove(Player player) { System.out.println(); System.out.println(currPlayer.getUserName()+"'s turn."); System.out.println("Press anything to roll the dice."); Scanner sc = new Scanner(System.in); char C = sc.next().charAt(0); int playerPosition = player.getPosition(); int rollValue = dice.roll(); int targetPosition = playerPosition + rollValue; if(targetPosition > board.getTotalCells()) System.out.println("Invalid Move"); else { if(board.hasSpecialEntity(targetPosition)) { targetPosition = board.getSpecialEntity(targetPosition).getEndPosition(); } } player.setPosition(targetPosition); } public void addPlayers(List<Player> all_players) { if(this.status == GameStatus.NOT_STARTED) { for(Player player : all_players) this.players.add(player); } else throw new GameAlreadyStartedException("Can't add players after game started") } }

Board.java

package snakeLadder; import lombok.Getter; public class Board{ @Getter int dimension; HashMap<Integer, SpecialEntity> specialEntities; public Board(int dimension) { this.dimension = dimension; } public void printBoard() { int totalCells = dimension*dimension; for(int i=totalCells; i > 0; i--) { System.out.print(" | " + i + " ") if(hasSpecialEntity(i)) System.out.print(specialEntities.get(i).getID()); System.out.print(" |"); if(totalCells % 10 == 0) System.out.println(); } } public int getTotalCells() { return this.dimesion * this.dimesion; } public void addSpecialEntity(SpecialEntity entity) { int actionPosition = entity.getActionPosition(); specialEntities.put(actionPosition, entity); } public boolean hasSpecialEntity(int position) { return specialEntities.containsKey(position); } public SpecialEntity getSpecialEntity(int position) { if(hasSpecialEntity(position)) return specialEntities.get(position); return null; }}

Dice.java

package snakeLadder; import lombok.Getter; public class Dice{ int maxValue; public Dice(int maxVal) { this.maxValue = maxVal; } public int roll() { return (int) Math.floor(Math.random()*maxValue + 1); }}

GameStatus.java

package snakeLadder; public enum GameStatus { NOT_STARTED, RUNNING, FINISHED}

SpecialEntity.java

package snakeLadder; import lombok.Getter;public abstract class BoardEntity { private int start; private int end; public SpecialEntity(int start, int end) { this.start = start; this.end = end; } public abstract String getID(); public int getActionPosition() { return this.start; } public int getEndPosition() { return this.end; }}

Snake.java

package snakeLadder; public class Snake extends SpecialEntity{ public Snake(int start, int end) { super(start, end); } @Override public String getID() { return "S_"+ this.getEnd(); } }

Ladder.java

package snakeLadder; public class Ladder extends SpecialEntity{ public Ladder(int start, int end) { super(start, end); } @Override public String getID() { return "L_"+ this.getEnd(); } }

Player.java

package snakeLadder; import lombok.Getter;import lombok.Setter; public class Player{ @Getter @Setter int position; @Getter String name; public Player(String name) { this.name = name; this.position = 0; }}

GameAlreadyStartedException.java

package snakeLadder; public class GameAlreadyStartedException extends Exception { public GameAlreadyStartedException(String message) { super(message); }}

It is important to structure the code into different classes with each class having a single responsibility (Remember S in SOLID Principles) and also having relations between the classes so that they can be easily extensible.

Some frequently asked low-level design examples to practice are:
  • Design Parking Lot
  • Design Splitwise
  • Design Tik Tok Toe Game
  • Design Car Rental System
  • Design Bookmyshow
  • Design Pub Sub System
  • Design Coffee Vending Machine
2.

How to Solve Low-Level Design problems in Interviews?

Answer»

Solving an LLD problem in an interview can be done easily if we divide the solution into multiple stages and focus on solving these stages one by one. LLD problems can be broadly categorized into 2 types: Standalone applications, and web applications.

Solving an LLD problem can be divided into mainly 3 stages:

1. Clarify & Gather Requirements: The low-level design interview questions are intentionally open-ended/ unstructured similar to real-life conditions. Ask the relevant questions regarding the problem (good questions are the ones that HELP to understand more about the system behaviour, features, and what features are expected to be added to the system in the future) and gather the complete requirements of the system. Don't assume anything beforehand and always clarify with the interview the assumptions you want to take. Write down the requirements & assumptions and discuss them with the interviewer.

2. Class Diagram & Use Case Diagram & Schema Diagram (If required): Once the requirements are gathered, DEFINE the core classes and objects, how the different classes interact with each other, and actors who interact with the system, the use cases for each actor, etc. Draw the class diagram and use a case diagram (can be optional, ask the interviewer) for the system. Define the relations between classes by observing the interactions between them. If Class Diagram & Use Case Diagram helps in representing the requirements of systems and the relationship between different classes, a Schema Diagram (also called an ER Diagram) helps in how the data models look and how to store the data in the database. Interviewers may not ask to write the code to store the data in the actual database but they may be interested in how the model looks like and the relationship between them. It is EASY to create the Schema Diagram from the Class Diagram. Each class in the class diagram becomes a table in Schema Diagram and the relationship between classes becomes the multiplicity between tables.

3. Code: FINALLY once the thoughts are structured using Class Diagram, Use Case Diagram, and Schema Diagram (if required), the Candidate can start writing the code. Apply the Design Patterns, Object-Oriented Principles & SOLID Principles wherever is possible to MAKE the system reusable, extensible, and maintainable. Make sure the code is well structured and follow the clean coding practices to make the classes and method clean. Don't try to fit design patterns to code but check if a given problem can be solved using any available design pattern. Take care of the readability of code while taking care of all of the above. Yes, software engineering is hard.

3.

How to prepare for Low-Level Design Interviews?

Answer»

Software Developers need to learn Low-Level Design not only to crack the Interviews but also to build modular, extensible, reusable, and maintainable software. It is the thought process that developers need to DEVELOP to effectively build the software from a set of requirements.

Here is the list of things that a software developer needs to learn for LLD Interviews:

  • Object-Oriented Language: The general expectation in the machine coding round (or) LLD round is that candidate writes Object Oriented Code. As the name suggests, Object-Oriented Languages revolve around everything about Objects. The candidate should identify the DIFFERENT entities that need to be created from the problem statement and model the classes as per the required entities along with choosing the right set of data structures depending on the use case.  Learning any Object-Oriented Language is a must as the candidate needs to write code using that language. Some of the popular Object-Oriented Languages are Java, C#, C++, and Python.
  • Object-Oriented Principles: Knowing an Object-Oriented Language itself is not sufficient for writing extensible and maintainable code. Many Object-Oriented principles are designed to make the software extensible and maintainable. Some of the well-known principles are :
    • YAGNI: You Ain't Gonna Need It is a practice in software development that states that features should only be added when required and thus help trim away excess and inefficiency development to FACILITATE the desired increased frequency of releases)
    • DRY: Don't Repeat Yourself is a principle that states that don't repeat the code again and again. If there is a code that is duplicated then whenever a change needs to be made, the change has to be done in both places. So the developer has to remember all the places where the code is duplicated which are difficult and error-prone. Thus this principle states that the code should never be duplicated and has to refactor into its method or class and all other places need to use this method/class instead of duplicating the code.
    • SOLID: These are a set of 5 principles. Single Responsibility, Open-Closed, Liskov Substitution, Interface Segregation, and Dependency Inversion.

Apart from these, there are well-known principles such as favouring composition over inheritance, Encapsulating what varies, Striving for loosely coupled classes, etc.

  • UML Diagrams: UML is an acronym that stands for Unified Modeling Language and is a standard for modelling, visualizing, and documenting the artefacts of software SYSTEMS. It is not a programming language but a tool to visually depict different types of diagrams that can be useful for building the software.
    • There are 14 different types of UML Diagrams and these 14 diagrams are classified into 2 high-level groups.
      •  Structural Diagrams: They represent the static view of the system. Class Diagram, Composite Structure Diagram, Object Diagram, Component Diagram, Deployment Diagram, Profile Diagram, and Package Diagram are part of Structural Diagrams.
      •  Behavioural Diagrams: They represent the dynamic view of the system. Activity Diagram, State Machine Diagram, Use Case Diagram, Interaction Overview Diagram, Timing Diagram, Sequence Diagram, and Communication Diagram are part of Behavioral Diagrams.

Class Diagram & Use Case Diagram are generally used in LLD rounds.

  • Design Patterns: Design Patterns are typical solutions to common problems in software design. "Don't reinvent the wheel" is a well-known phrase in software engineering. If a problem is already solved, don't solve the same problem to get the same solution. Instead, use the solution to the problem. Similarly, there are a lot of common problems in software design that are solved and are given as a toolkit called Design Patterns. Design Patterns are not specific to a particular language. They are the general solutions that specify how a design problem can be solved and hence can be implemented in any language. These design patterns are proven and tested and hence make the development process smooth and easy.
  • Practice LLD Questions: Try to practice as many low-level design interview questions as possible. Solving different problems gives different perspectives and thereby improves design skills. There is no right solution for design problems as opposed to data structures and algorithmic problems. So solving different problems gives different ideas and thus develops the overall thought process for solving any design problem.
4.

Why LLD is Important?

Answer»

As a software developer in any company, the objective is to build software for the business of the company. Building software is a complex task. Change is the only constant thing in the world. As the software progresses over the years, it needs to incorporate a lot of changes as the requirements keep on changing. We can choose to build software in many ways but we NEED to build it in such a way that the software is maintainable and extensible over the years easily. 

Most of the software developer interviews have Data Structures & Algorithms round(s). But it is not often for software developers to USE these data structures and algorithms in the real world while building software. (If you are an experienced candidate, can you recall when was the last time you used the Dijkstra algorithm? If you are fresher, ask any of your senior colleagues the same question. )

On the other hand, Low-Level Design is a must for building a piece of software. As LLD focuses on how to build software from a set of requirements, how different components interact with each other, what responsibilities each component has etc, it is a vital exercise to be done before actually writing the CODE. Writing code is the easiest part of building software if we have the designs already in place. Maintaining and Extending software will be easy if designs are well thought of.

As we can see from the above picture, Maintenance takes almost 70% of the effort in the software development LIFE cycle. So the software should be easily maintainable and extensible. LLD plays an important role in the design of software and hence directly contributes to the maintainability and extensibility of software.