Skip to content

Implementation of Snakes & Ladders LLD #154

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
285 changes: 285 additions & 0 deletions snakesAndLadders.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,285 @@
#include <iostream>
#include <vector>
#include <cstdlib>
#include <unordered_map>
#include <algorithm>

using namespace std;

class OutOfRangeError {};

class InvalidLadderError {};

class InvalidSnakeError {};

class GameComponent {
public:
virtual void setTerminals(int, int) = 0;

protected:
int head;
int tail;
unordered_map<int, int> terminals;
};

class Snake : public GameComponent {
public:
void setTerminals(int head, int tail) override {
this->head = head;
this->tail = tail;
}

friend class Snakes;
};

class Ladder : public GameComponent {
public:
void setTerminals(int start, int end) override {
this->head = start;
this->tail = end;
}

friend class Ladders;
};

class Player {
public:
Player() {
currPos = 0;
}

void setName(string name) {
this->name = name;
}

void moveBy(int moves) {
if(currPos + moves > MAX_POS) {
return;
}
currPos += moves;
}

void moveTo(int finalPos) {
currPos = finalPos;
}

int getCurrPos() {
return currPos;
}

string getName() {
return name;
}

private:
string name;
int currPos;
static constexpr int MAX_POS = 100;
};

class Game;

class ComponentsGroup {
public:
virtual void setup(int) = 0;
};

class Snakes : public ComponentsGroup {
public:
void setup(int noOfSnakes) override {
int head, tail;
for(int i = 0; i < noOfSnakes; ++i) {
Snake* snake = new Snake();
try {
cin >> head >> tail;
if(head > 100 || head < 0 || tail > 100 || tail < 0) {
throw OutOfRangeError();
} else if(tail > head) {
throw InvalidSnakeError();
}
listOfSnakes[head] = tail;
snake->setTerminals(head, tail);
}
catch(OutOfRangeError &E) {
cout << "Out of range error. Try again." << endl;
--i;
}
catch(InvalidSnakeError &E) {
cout << "Tail must be less than Head. Try again." << endl;
--i;
}
}
}

friend class Game;

private:
unordered_map<int,int> listOfSnakes;
};

class Ladders : public ComponentsGroup {
public:
void setup(int noOfLadders) override {
int start, end;
for(int i = 0; i < noOfLadders; ++i) {
Ladder *ladder = new Ladder;
try {
cin >> start >> end;
if(start < 0 || end > 100 || start > 100 || end < 0) {
throw OutOfRangeError();
} else if(start > end) {
throw InvalidLadderError();
}
listOfLadders[start] = end;
ladder->setTerminals(start, end);
}
catch(OutOfRangeError &E) {
cout << "Out of range error. Try again." << endl;
--i;
}
catch(InvalidLadderError &E) {
cout << "Start must be greater than End. Try again." << endl;
--i;
}
}
}

friend class Game;

private:
unordered_map<int, int> listOfLadders;
};

class Players {
public:
void setup(int noOfPlayers) {
for(int i = 0; i < noOfPlayers; ++i) {
Player *player = new Player();
string name; cin >> name;
player->setName(name);
listOfPlayers.push_back(player);
}
}

vector<Player*> getListOfPlayers() {
return listOfPlayers;
}

friend class Game;

private:
vector<Player*> listOfPlayers;
};

class Dice {
public:
static void rollDice() {
face = 1 + (rand() % MAX_FACE_VALUE);
}

static int getFace() {
return face;
}

private:
static constexpr int MAX_FACE_VALUE = 6;
static int face;
};

int Dice::face = 1;

class Game {
public:
Game() {
turn = 0;
}

Game* setup();

void play();

void updateTurn() {
turn = (turn + 1) % noOfPlayers;
}

bool isBittenBySnake(Player *&player) const {
return snakes->listOfSnakes.find(player->getCurrPos()) != snakes->listOfSnakes.end();
}

bool hasFoundALadder(Player *&player) const {
return ladders->listOfLadders.find(player->getCurrPos()) != ladders->listOfLadders.end();
}

int getTurn() {
return turn;
}

int getFinalPos(unordered_map<int, int> posMatrix) {
return posMatrix[(players->listOfPlayers)[getTurn()]->getCurrPos()];
}

private:
Snakes *snakes;
Ladders *ladders;
Players* players;
int turn;
int noOfSnakes;
int noOfLadders;
int noOfPlayers;
};

Game* Game::setup() {
cout << "Enter number of snakes: ";
cin >> noOfSnakes;
snakes = new Snakes();
snakes->setup(noOfSnakes);

cout << "Enter number of ladders: ";
cin >> noOfLadders;
ladders = new Ladders();
ladders->setup(noOfLadders);

cout << "Enter number of players: ";
cin >> noOfPlayers;
players = new Players();
players->setup(noOfPlayers);

return this;
}

void Game::play() {
Player *currPlayer;
while(true) {
currPlayer = players->listOfPlayers[getTurn()];
int initPos = currPlayer->getCurrPos();

Dice::rollDice();
currPlayer->moveBy(Dice::getFace());

while(isBittenBySnake(currPlayer) || hasFoundALadder(currPlayer)) {
if(isBittenBySnake(currPlayer)) {
currPlayer->moveTo(getFinalPos(snakes->listOfSnakes));
} else {
currPlayer->moveTo(getFinalPos(ladders->listOfLadders));
}
}

cout << currPlayer->getName() << " rolled a " << Dice::getFace() << " and moved from " << initPos << " to " << currPlayer->getCurrPos() << endl;

if(currPlayer->getCurrPos() == 100) {
cout << currPlayer->getName() << " wins the game." << endl;
break;
}

updateTurn();
}
delete currPlayer;
currPlayer = nullptr;
}

int main() {
Game *newGame = new Game();
newGame->setup();
newGame->play();
return 0;
}