130. Design Snake and Ladder Game


Design Snake and Ladder Game
Design a Snake and Ladder game simulator.

The game is played on a standard Snake and Ladder board with 100 numbered cells. Cell 1 is the starting position and cell 100 is the winning position.

The game supports multiple players and follows round-robin turn order. Multiple players may stay on the same cell at the same time without any interaction.

Some cells contain ladders. Landing on the start of a ladder immediately moves the player to a higher-numbered cell.

Some cells contain snakes. Landing on the head of a snake immediately moves the player to a lower-numbered cell.

In the classic game, dice values are random. In this problem, a valid player id and a valid list of dice values for exactly one turn are provided directly in the method call instead of generating random rolls.

The list represents all dice rolls made by the player during that one turn. Most turns contain only one value. If the player rolls a 6, the player gets an extra roll in the same turn, so the list may contain more values.

If the list contains exactly two consecutive sixes, the effective dice value for that turn is the sum of all values in the list.
For example, [6,2] means effective dice value 8 and [6,6,3] means effective dice value 15.

If the list contains three consecutive sixes, the effective dice value for that turn becomes 0 immediately. In that case, the player does not move at all and the turn ends.

There will be at most 3 values in the dice list for a turn.

On a turn, the specified player moves forward by the effective dice value of that turn. If the move goes beyond cell 100, the player does not move. A player must reach cell 100 exactly to win.

If playTurn is called for a player who is not the current player, return exactly "INVALID MOVE" and do not change any game state.

Once a player wins, the game is over and no further moves should change the game state. On the exact turn when a player wins, playTurn returns "WIN". After the game has already been won, every later call to playTurn returns "GAME COMPLETED" and does nothing.

  • A snake will never intersect with a ladder, either at head or tail.
  • There will never be any snake or ladder head or tail on start cell 1 or end cell 100.
  • A turn applies at most one snake or one ladder move after the normal movement because the board definitions never create snake-ladder chaining conflicts.

Class

SnakeAndLadderGame

Top Methods

Constructor

SnakeAndLadderGame(List<String> playerIds, List<String> snakes, List<String> ladders)
  • playerIds contains the players in turn order.
  • Each value in snakes is in the format "head,tail".
  • Each value in ladders is in the format "start,end".
  • For every snake, 1 < tail < head < 100.
  • For every ladder, 1 < start < end < 100.
  • No cell is the start of more than one snake or ladder.
  • All players start at cell 1.
  • The first turn belongs to playerIds.get(0).

Play Turn

String playTurn(String playerId, List<Integer> diceValues)
  • playerId is a valid player id already present in the game.
  • diceValues contains all dice rolls for exactly one turn.
  • 1 ≤ diceValues.size() ≤ 3.
  • Each value in diceValues is between 1 and 6.
  • If diceValues.size() == 2, then diceValues.get(0) == 6.
  • If diceValues.size() == 3, then diceValues.get(0) == 6 and diceValues.get(1) == 6.
  • If diceValues is [6,6,6], the effective dice value for the turn is 0 and the player does not move.
  • Otherwise, the effective dice value is the sum of all values in diceValues.
  • If the game was already completed before this call, return exactly "GAME COMPLETED".
  • If playerId is not the current player, return exactly "INVALID MOVE" and do not change any game state.
  • If the move goes beyond 100, the player stays on the same cell.
  • If the player lands on a snake head, move immediately to its tail.
  • If the player lands on a ladder start, move immediately to its end.
  • If the player reaches exactly 100, that player wins and the game ends.
  • If the player wins in this turn, return exactly "WIN".
  • Otherwise, return the player's final cell after the turn in the format "playerId,cell,nextPlayerId,CONTINUE".
  • For a non-winning valid turn, nextPlayerId is always the next player in round-robin order because the full turn has already been captured inside diceValues.

Get Player Position

int getPlayerPosition(String playerId)
  • playerId is a valid player id already present in the game.
  • Return the current cell number occupied by the player.

Get Winner

String getWinner()
  • Return the winner's player id if the game has been won.
  • Return an empty string if no player has won yet.

Constraints

  • 2 ≤ playerIds.size() ≤ 10
  • 0 ≤ snakes.size() ≤ 20
  • 0 ≤ ladders.size() ≤ 20
  • Each player id is non-empty and unique.
  • Snake and ladder definitions are valid and do not conflict.
  • 1 ≤ diceValues.size() ≤ 3 for every turn.
  • Each roll inside diceValues is between 1 and 6.
  • If diceValues.size() == 2, the first value is 6.
  • If diceValues.size() == 3, the first two values are both 6.
  • Calls may be made for a valid player even when it is not that player's turn.
  • In that case, playTurn must return "INVALID MOVE" and leave the full game state unchanged.
  • You must never use null as any parameter value.

Examples

Example 1

Input
SnakeAndLadderGame(playerIds = ["A","B"], snakes = ["17,7","54,34","62,19","98,79"], ladders = ["3,22","5,8","11,26","20,29"])

playTurn(playerId = "A", diceValues = [2]) returns "A,22,B,CONTINUE"
playTurn(playerId = "B", diceValues = [4]) returns "B,8,A,CONTINUE"
playTurn(playerId = "A", diceValues = [6,3]) returns "A,31,B,CONTINUE"
getPlayerPosition(playerId = "A") returns 31
getPlayerPosition(playerId = "B") returns 8
getWinner() returns ""

Explanation
Player A moves from 1 to 3 and climbs the ladder to 22. Player B moves from 1 to 5 and climbs the ladder to 8. Then A takes a turn with dice list [6,3], so the effective dice value is 9. A moves from 22 to 31.

Example 2

Input
SnakeAndLadderGame(playerIds = ["P1","P2"], snakes = ["14,4"], ladders = ["9,31"])

playTurn(playerId = "P1", diceValues = [6,6,1]) returns "P1,4,P2,CONTINUE"
getPlayerPosition(playerId = "P1") returns 4

Explanation
The dice list is [6,6,1], so the effective dice value is 13. P1 moves from 1 to 14, lands on a snake, and moves down to 4.

Example 3

Input
SnakeAndLadderGame(playerIds = ["R","S"], snakes = [], ladders = [])

playTurn(playerId = "R", diceValues = [6,6,6]) returns "R,1,S,CONTINUE"
getPlayerPosition(playerId = "R") returns 1
getPlayerPosition(playerId = "S") returns 1

Explanation
Three consecutive sixes make the effective dice value 0. Player R does not move and remains at cell 1. The turn ends and the next turn belongs to S.

Example 4

Input
SnakeAndLadderGame(playerIds = ["X","Y"], snakes = ["80,60"], ladders = ["94,100"])

playTurn(playerId = "Y", diceValues = [1]) returns "INVALID MOVE"
getPlayerPosition(playerId = "X") returns 1
getPlayerPosition(playerId = "Y") returns 1
playTurn(playerId = "X", diceValues = [6,6,3]) returns "X,16,Y,CONTINUE"
playTurn(playerId = "Y", diceValues = [1]) returns "Y,2,X,CONTINUE"
playTurn(playerId = "X", diceValues = [6,6,3]) returns "X,31,Y,CONTINUE"
playTurn(playerId = "Y", diceValues = [1]) returns "Y,3,X,CONTINUE"
playTurn(playerId = "X", diceValues = [6,6,3]) returns "X,46,Y,CONTINUE"
playTurn(playerId = "Y", diceValues = [1]) returns "Y,4,X,CONTINUE"
playTurn(playerId = "X", diceValues = [6,6,3]) returns "X,61,Y,CONTINUE"
playTurn(playerId = "Y", diceValues = [1]) returns "Y,5,X,CONTINUE"
playTurn(playerId = "X", diceValues = [6,6,3]) returns "X,76,Y,CONTINUE"
playTurn(playerId = "Y", diceValues = [1]) returns "Y,6,X,CONTINUE"
playTurn(playerId = "X", diceValues = [4]) returns "X,60,Y,CONTINUE"
playTurn(playerId = "Y", diceValues = [1]) returns "Y,7,X,CONTINUE"
playTurn(playerId = "X", diceValues = [6,6,6]) returns "X,60,Y,CONTINUE"
playTurn(playerId = "Y", diceValues = [1]) returns "Y,8,X,CONTINUE"
playTurn(playerId = "X", diceValues = [6,6,6]) returns "X,60,Y,CONTINUE"
playTurn(playerId = "Y", diceValues = [1]) returns "Y,9,X,CONTINUE"
playTurn(playerId = "X", diceValues = [6,6,6]) returns "X,60,Y,CONTINUE"
playTurn(playerId = "Y", diceValues = [1]) returns "Y,10,X,CONTINUE"
playTurn(playerId = "X", diceValues = [6,6,6]) returns "X,60,Y,CONTINUE"
playTurn(playerId = "Y", diceValues = [1]) returns "Y,11,X,CONTINUE"
playTurn(playerId = "X", diceValues = [6,6,6]) returns "X,60,Y,CONTINUE"
playTurn(playerId = "Y", diceValues = [1]) returns "Y,12,X,CONTINUE"
playTurn(playerId = "X", diceValues = [6,6,6]) returns "X,60,Y,CONTINUE"
playTurn(playerId = "Y", diceValues = [1]) returns "Y,13,X,CONTINUE"
playTurn(playerId = "X", diceValues = [6,6,6]) returns "X,60,Y,CONTINUE"
playTurn(playerId = "Y", diceValues = [1]) returns "Y,14,X,CONTINUE"
playTurn(playerId = "X", diceValues = [6,6,6]) returns "X,60,Y,CONTINUE"
playTurn(playerId = "Y", diceValues = [1]) returns "Y,15,X,CONTINUE"
playTurn(playerId = "X", diceValues = [6,6,3]) returns "X,75,Y,CONTINUE"
playTurn(playerId = "Y", diceValues = [1]) returns "Y,16,X,CONTINUE"
playTurn(playerId = "X", diceValues = [6,6,3]) returns "X,90,Y,CONTINUE"
playTurn(playerId = "Y", diceValues = [1]) returns "Y,17,X,CONTINUE"
playTurn(playerId = "X", diceValues = [4]) returns "WIN"
getWinner() returns "X"
playTurn(playerId = "Y", diceValues = [1]) returns "GAME COMPLETED"

Explanation
The first call is invalid because the first turn belongs to X, not Y, so the method returns "INVALID MOVE" and both players remain at cell 1. Later, when X moves from 76 by 4, X lands on snake head 80 and immediately drops to 60. Several [6,6,6] turns keep X at 60 because the effective dice value is 0. After that, X reaches 90. On the final turn, X plays [4], lands on ladder start 94, climbs to 100, and wins exactly. Any later call to playTurn returns "GAME COMPLETED".




Please use Laptop/Desktop or any other large screen to add/edit code.