diff --git a/.gitignore b/.gitignore index 36b741e6..a4f439df 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,8 @@ tests/out .DS_Store .* !.gitignore + +**/out +.target +**/target +*.iml \ No newline at end of file diff --git a/docs/clone-1.png b/docs/clone-1.png deleted file mode 100644 index e0df3b2f..00000000 Binary files a/docs/clone-1.png and /dev/null differ diff --git a/docs/clone.png b/docs/clone.png deleted file mode 100644 index e3bde132..00000000 Binary files a/docs/clone.png and /dev/null differ diff --git a/docs/fork.png b/docs/fork.png deleted file mode 100644 index 62014114..00000000 Binary files a/docs/fork.png and /dev/null differ diff --git a/docs/git.md b/docs/git.md deleted file mode 100644 index bba78f4a..00000000 --- a/docs/git.md +++ /dev/null @@ -1,83 +0,0 @@ -# Create Github Account -1. Create account at: https://github.com/join by choosing an unique username -2. Check your email for verification email and click on verification link - -# Install Git Locally - -## Windows -- Download git from https://gitforwindows.org/ -- When you've successfully started the installer, you should see the Git Setup wizard screen. Follow the Next and Finish prompts to complete the installation. The default options are pretty sensible for most users. -- Open a Command Prompt (or Git Bash if during installation you elected not to use Git from the Windows Command Prompt). -- Run the following commands to configure your Git username and email using the following commands, replacing Emma's name and email with your own. These details will be associated with any commits that you create: -``` -git config --global user.name "Emma Paris" -git config --global user.email "eparis@atlassian.com" -``` - -## Linux -- From your shell, install Git using apt-get: -``` -sudo apt-get update -sudo apt-get install git -``` -- Verify the installation was successful by typing git --version which should return the version number: -``` -git --version -``` -- Run the following commands to configure your Git username and email using the following commands, replacing Emma's name and email with your own. These details will be associated with any commits that you create: -``` -git config --global user.name "Emma Paris" -git config --global user.email "eparis@atlassian.com" -``` - -## Mac -- From your shell, install Git using Homebrew: -``` -brew install git -``` -- Verify the installation was successful by typing git --version which should return the version number: -``` -git --version -``` -- Run the following commands to configure your Git username and email using the following commands, replacing Emma's name and email with your own. These details will be associated with any commits that you create: -``` -git config --global user.name "Emma Paris" -git config --global user.email "eparis@atlassian.com" -``` - -These commands have been taken from Atlassian's website. - -# Fork -- In the repository page, click on "Fork" -![Fork](./fork.png) -- After clicking on Fork, you'll be redirected to a new page with a copy of the repository. -- This new repository is where you'll make your code changes. -- Then click on clone in this new page - -# Clone -- In the repository page, click on "Clone or download" - -![Clone](./clone.png) - -- Then click on copy link button - -![Clone-1](./clone-1.png) - -- Go to the terminal and clone the repository on your machine by typing: -```git clone``` followed by the link you copied in previous step and hit enter. - -# Push local changes to remote -Execute these commands on the terminal: -- ```cd machine-coding-feedback``` -- ```git add .``` -- ```git commit -m "solved the problem"``` -- ```git push``` - -# PR -- Open the repository in your profile. The URL would be of this format: ```https://github.com//machine-coding-feedback``` -- Click on "New Pull Request". -![pr](./pr.png) -- Then click on "Create pull request" in the page that opened. -![pr-1](./pr-1.png) -- Again click on the new button that says "Create pull request" -- After this step, a new page would load which would be your pull request. diff --git a/docs/index.md b/docs/index.md deleted file mode 100644 index 4f62c017..00000000 --- a/docs/index.md +++ /dev/null @@ -1,45 +0,0 @@ -# Please go through this document to get your machine coding code reviewed by workat.tech - -## Why Practice for Machine Coding Round? -- In companies like Flipkart, Uber, Swiggy, Ola, Cred, etc the first onsite round is the machine coding round. -- You're given a design problem (like design a parking lot) with a set of requirements. -- Then you need to create a clean, modular and extensible coding solution for the same. -- The code is supposed to be written in a matter of 90 mins. -- After the round, you sit with an interviewer who goes through your code and tries to understand your design decisions and also tries to see if your code works for all the requirements. -- The interviewer may ask you to extend your solution based on some new requirement. -- It is a pretty crucial round since most of the people get eliminated in this round and it is completely different from what everyone generally practices for. - -## How to prepare? -Please go through our article on 'How to prepare for machine coding round?'. - -## Setup -- Ensure that you've a github account. If you do not have one, check this page. -- Ensure that you've git set up locally on your Laptop/PC. If it is not set up, check this page. -- Go to machine-coding-feedback repository. -- Fork the repository. If you're new to git, follow the steps mentioned in the fork section here -- Clone the repository in your local machine.If you're new to git, follow the steps mentioned in the clone section here - -## Coding -- After the setup step, a new folder will be created in your laptop/PC with the name: machine-coding-feedback. -- Open that folder in an IDE of your choice and start coding. - -## Expectations -- Make sure that you have a working and demonstrable code -- Make sure that the code is functionally correct -- Code should be modular and readable -- Separation of concern should be addressed -- Please do not write everything in a single file -- Code should easily accommodate new requirements and minimal changes -- There should be a main method from where the code could be easily testable -- [Optional] Write unit tests, if possible -- No need to create a GUI - -## Submission -- After you're done with coding, you need to commit and push your changes to github. -- You should push your changes to the master branch of your forked repository. If you're new to git, follow the steps mentioned in the push local changes to remote section here -- Create a pull request to our master branch. If you're new to git, follow the steps mentioned in the PR section here - -## Evaluation -- We'll be reviewing everyone's submission and try to provide feedback on how to improve through code review comments on GitHub. -- We also have some volunteers who will help with the review. -- Anyone can volunteer to review. diff --git a/docs/pr-1.png b/docs/pr-1.png deleted file mode 100644 index 3ade58aa..00000000 Binary files a/docs/pr-1.png and /dev/null differ diff --git a/docs/pr.png b/docs/pr.png deleted file mode 100644 index d798f596..00000000 Binary files a/docs/pr.png and /dev/null differ diff --git a/pom.xml b/pom.xml new file mode 100644 index 00000000..2c2fe145 --- /dev/null +++ b/pom.xml @@ -0,0 +1,55 @@ + + + 4.0.0 + + org.aghorii + snake-and-ladder + 0.0.1 + + + 1.8 + 1.8 + + + + + org.junit.jupiter + junit-jupiter-api + 5.7.0 + test + + + org.junit.jupiter + junit-jupiter-engine + 5.7.0 + test + + + + + org.mockito + mockito-core + 3.6.0 + test + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 1.8 + 1.8 + + + + + + + \ No newline at end of file diff --git a/snake-and-ladder/src/main/java/in/aghorii/snakeandladder/Application.java b/snake-and-ladder/src/main/java/in/aghorii/snakeandladder/Application.java new file mode 100644 index 00000000..6bfddee9 --- /dev/null +++ b/snake-and-ladder/src/main/java/in/aghorii/snakeandladder/Application.java @@ -0,0 +1,8 @@ +package in.aghorii.snakeandladder; + +public class Application { + + public static void main(String[] args) { + GameExecutor.execute(); + } +} \ No newline at end of file diff --git a/snake-and-ladder/src/main/java/in/aghorii/snakeandladder/GameExecutor.java b/snake-and-ladder/src/main/java/in/aghorii/snakeandladder/GameExecutor.java new file mode 100644 index 00000000..482341f3 --- /dev/null +++ b/snake-and-ladder/src/main/java/in/aghorii/snakeandladder/GameExecutor.java @@ -0,0 +1,105 @@ +package in.aghorii.snakeandladder; + +import in.aghorii.snakeandladder.model.*; +import in.aghorii.snakeandladder.service.GameService; +import in.aghorii.snakeandladder.service.creator.BoardCreator; +import in.aghorii.snakeandladder.util.PropertyInjector; +import in.aghorii.snakeandladder.util.PropertyLoader; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.List; + +public class GameExecutor { + private static final List snakes = new ArrayList<>(); + private static final List ladders = new ArrayList<>(); + private static final List players = new ArrayList<>(); + + public GameExecutor() {} + + public static void execute() { + Board board = injectPropertyAndCreateBoard(); + GameService gameService = new GameService(board); + String winner = gameService.startGameAndProvideWinner(); + + System.out.println(winner + " wins the game\n"); + } + + private static Board injectPropertyAndCreateBoard() { + BoardCreator boardCreator = getBoardCreator(); + extractGameElements(); + + return boardCreator.createBoard(snakes, ladders, players); + } + + private static BoardCreator getBoardCreator() { + BoardCreator boardCreator = new BoardCreator(); + PropertyLoader propertyLoader = new PropertyLoader("config.properties"); + PropertyInjector injector = new PropertyInjector(propertyLoader); + injector.inject(boardCreator); + + return boardCreator; + } + + private static void extractGameElements() { + + try (InputStream inputStream = GameExecutor.class.getClassLoader().getResourceAsStream("snake&ladder.txt")) { + if (inputStream == null) { + System.out.println("Could not find snake&ladder.txt file"); + throw new RuntimeException("Could not find snake&ladder.txt file"); + } + + processFile(inputStream); + } catch (IOException ex) { + System.out.println("Could not read snake&ladder.txt file"); + throw new RuntimeException("Could not read snake&ladder.txt file"); + } + } + + private static void processFile(InputStream inputStream) { + + try(BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { + String line; + + //Populate snakes + line = reader.readLine(); + int n = Integer.parseInt(line); + for(int i=0; i snakes; + private final List ladders; + private List players; + + private Board(BoardBuilder builder) { + this.snakes = builder.snakes; + this.ladders = builder.ladders; + this.players = builder.players; + this.boardSize = builder.boardSize; + } + + public int getBoardSize() { + return boardSize; + } + + public List getSnakes() { + return snakes; + } + + public List getLadders() { + return ladders; + } + + public List getPlayers() { + return players; + } + + public void setPlayers(List players) { + this.players = players; + } + + public static class BoardBuilder { + + private int boardSize; + private List snakes; + private List ladders; + private List players; + + public BoardBuilder() {} + + public BoardBuilder boardSize(int boardSize) { + this.boardSize = boardSize; + return this; + } + + public BoardBuilder snakes(List snakes) { + this.snakes = snakes; + return this; + } + + public BoardBuilder ladders(List ladders) { + this.ladders = ladders; + return this; + } + + public BoardBuilder players(List players) { + this.players = players; + return this; + } + + public Board build() { + return new Board(this); + } + } +} diff --git a/snake-and-ladder/src/main/java/in/aghorii/snakeandladder/model/GameElement.java b/snake-and-ladder/src/main/java/in/aghorii/snakeandladder/model/GameElement.java new file mode 100644 index 00000000..7e41f4d4 --- /dev/null +++ b/snake-and-ladder/src/main/java/in/aghorii/snakeandladder/model/GameElement.java @@ -0,0 +1,7 @@ +package in.aghorii.snakeandladder.model; + +public enum GameElement { + SNAKES, + LADDERS, + PLAYERS; +} diff --git a/snake-and-ladder/src/main/java/in/aghorii/snakeandladder/model/Ladder.java b/snake-and-ladder/src/main/java/in/aghorii/snakeandladder/model/Ladder.java new file mode 100644 index 00000000..d4df0db3 --- /dev/null +++ b/snake-and-ladder/src/main/java/in/aghorii/snakeandladder/model/Ladder.java @@ -0,0 +1,20 @@ +package in.aghorii.snakeandladder.model; + +public class Ladder { + + private final int start; + private final int end; + + public Ladder(int start, int end) { + this.start = start; + this.end = end; + } + + public int getStart() { + return start; + } + + public int getEnd() { + return end; + } +} diff --git a/snake-and-ladder/src/main/java/in/aghorii/snakeandladder/model/Player.java b/snake-and-ladder/src/main/java/in/aghorii/snakeandladder/model/Player.java new file mode 100644 index 00000000..a285d206 --- /dev/null +++ b/snake-and-ladder/src/main/java/in/aghorii/snakeandladder/model/Player.java @@ -0,0 +1,24 @@ +package in.aghorii.snakeandladder.model; + +public class Player { + + private final String name; + private int position; + + public Player(String name) { + this.name = name; + position = 0; + } + + public String getName() { + return name; + } + + public int getPosition() { + return position; + } + + public void setPosition(int position) { + this.position = position; + } +} diff --git a/snake-and-ladder/src/main/java/in/aghorii/snakeandladder/model/Snake.java b/snake-and-ladder/src/main/java/in/aghorii/snakeandladder/model/Snake.java new file mode 100644 index 00000000..5bf8b432 --- /dev/null +++ b/snake-and-ladder/src/main/java/in/aghorii/snakeandladder/model/Snake.java @@ -0,0 +1,20 @@ +package in.aghorii.snakeandladder.model; + +public class Snake { + + private final int head; + private final int tail; + + public Snake(int head, int tail) { + this.head = head; + this.tail = tail; + } + + public int getHead() { + return head; + } + + public int getTail() { + return tail; + } +} diff --git a/snake-and-ladder/src/main/java/in/aghorii/snakeandladder/service/GameService.java b/snake-and-ladder/src/main/java/in/aghorii/snakeandladder/service/GameService.java new file mode 100644 index 00000000..46b6a3c2 --- /dev/null +++ b/snake-and-ladder/src/main/java/in/aghorii/snakeandladder/service/GameService.java @@ -0,0 +1,85 @@ +package in.aghorii.snakeandladder.service; + +import in.aghorii.snakeandladder.model.Board; +import in.aghorii.snakeandladder.model.Ladder; +import in.aghorii.snakeandladder.model.Player; +import in.aghorii.snakeandladder.model.Snake; + +import java.util.List; +import java.util.Random; + +public class GameService { + + private final Board board; + + public GameService(Board board) { + this.board = board; + } + + public String startGameAndProvideWinner() { + List players = board.getPlayers(); + return startGame(players); + } + + private String startGame(List players) { + + int playerCount = players.size(); + int currentPlayerIndex = 0; + boolean winnerFound = false; + + while(!winnerFound) { + Player currentPlayer = players.get(currentPlayerIndex); + int currentPosition = currentPlayer.getPosition(); + + int diceNumber = rollDice(); + winnerFound = executeTurn(currentPlayer, diceNumber); + + System.out.println(currentPlayer.getName() + " rolled a " + diceNumber + " and moved from " + + currentPosition + " to " + currentPlayer.getPosition()); + + if (!winnerFound) { + currentPlayerIndex++; + if(currentPlayerIndex == playerCount) { + currentPlayerIndex = 0; + } + } + } + + return players.get(currentPlayerIndex).getName(); + } + + private boolean executeTurn(Player player, int diceNumber) { + if ((player.getPosition() + diceNumber) > board.getBoardSize()) { + return false; + } + player.setPosition(player.getPosition() + diceNumber); + + if (player.getPosition() == board.getBoardSize()) { + return true; + } + checkForSnakeOrLadder(player); + + return player.getPosition() == board.getBoardSize(); + } + + private void checkForSnakeOrLadder(Player player) { + for (Snake snake : board.getSnakes()) { + if (player.getPosition() == snake.getHead()) { + player.setPosition(snake.getTail()); + checkForSnakeOrLadder(player); + } + } + + for (Ladder ladder : board.getLadders()) { + if (player.getPosition() == ladder.getStart()) { + player.setPosition(ladder.getEnd()); + checkForSnakeOrLadder(player); + } + } + } + + private int rollDice() { + Random random = new Random(); + return random.nextInt(6) + 1; + } +} diff --git a/snake-and-ladder/src/main/java/in/aghorii/snakeandladder/service/creator/BoardCreator.java b/snake-and-ladder/src/main/java/in/aghorii/snakeandladder/service/creator/BoardCreator.java new file mode 100644 index 00000000..f74ed78b --- /dev/null +++ b/snake-and-ladder/src/main/java/in/aghorii/snakeandladder/service/creator/BoardCreator.java @@ -0,0 +1,28 @@ +package in.aghorii.snakeandladder.service.creator; + +import in.aghorii.snakeandladder.model.Board; +import in.aghorii.snakeandladder.model.Ladder; +import in.aghorii.snakeandladder.model.Player; +import in.aghorii.snakeandladder.model.Snake; +import in.aghorii.snakeandladder.util.annotation.InjectProperty; + +import java.util.List; + +public class BoardCreator{ + + @InjectProperty(value = "board.size") + private int boardSize; + + public BoardCreator() {} + + public Board createBoard(List snakes, List ladders, List players) { + return new Board + .BoardBuilder() + .boardSize(boardSize) + .snakes(snakes) + .ladders(ladders) + .players(players) + .build(); + } + +} diff --git a/snake-and-ladder/src/main/java/in/aghorii/snakeandladder/util/PropertyInjector.java b/snake-and-ladder/src/main/java/in/aghorii/snakeandladder/util/PropertyInjector.java new file mode 100644 index 00000000..8c4055c5 --- /dev/null +++ b/snake-and-ladder/src/main/java/in/aghorii/snakeandladder/util/PropertyInjector.java @@ -0,0 +1,34 @@ +package in.aghorii.snakeandladder.util; + +import in.aghorii.snakeandladder.util.annotation.InjectProperty; + +import java.lang.reflect.Field; + +public class PropertyInjector { + private final PropertyLoader propertyLoader; + + public PropertyInjector(PropertyLoader propertyLoader) { + this.propertyLoader = propertyLoader; + } + + public void inject(Object obj) { + Field[] fields = obj.getClass().getDeclaredFields(); + + for (Field field : fields) { + if (field.isAnnotationPresent(InjectProperty.class)) { + InjectProperty annotation = field.getAnnotation(InjectProperty.class); + String propertyValue = propertyLoader.getProperty(annotation.value()); + + if (propertyValue != null) { + field.setAccessible(true); + try { + int intValue = Integer.parseInt(propertyValue); + field.set(obj, intValue); + } catch (IllegalAccessException e) { + System.out.println("Error injecting property " + field.getName() + " to " + obj.getClass().getName()); + } + } + } + } + } +} diff --git a/snake-and-ladder/src/main/java/in/aghorii/snakeandladder/util/PropertyLoader.java b/snake-and-ladder/src/main/java/in/aghorii/snakeandladder/util/PropertyLoader.java new file mode 100644 index 00000000..584078d0 --- /dev/null +++ b/snake-and-ladder/src/main/java/in/aghorii/snakeandladder/util/PropertyLoader.java @@ -0,0 +1,26 @@ +package in.aghorii.snakeandladder.util; + +import java.io.InputStream; +import java.io.IOException; +import java.util.Properties; + +public class PropertyLoader { + private final Properties properties; + + public PropertyLoader(String propertyFileName) { + properties = new Properties(); + try(InputStream input = getClass().getClassLoader().getResourceAsStream(propertyFileName)) { + if (input == null) { + System.out.println("Property file not found: " + propertyFileName); + return; + } + properties.load(input); + } catch(IOException ex) { + System.out.println("Could not load property file: " + propertyFileName); + } + } + + public String getProperty(String propertyName){ + return properties.getProperty(propertyName); + } +} diff --git a/snake-and-ladder/src/main/java/in/aghorii/snakeandladder/util/annotation/InjectProperty.java b/snake-and-ladder/src/main/java/in/aghorii/snakeandladder/util/annotation/InjectProperty.java new file mode 100644 index 00000000..3ccafcf5 --- /dev/null +++ b/snake-and-ladder/src/main/java/in/aghorii/snakeandladder/util/annotation/InjectProperty.java @@ -0,0 +1,9 @@ +package in.aghorii.snakeandladder.util.annotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface InjectProperty { + String value() default ""; +} diff --git a/snake-and-ladder/src/main/resources/config.properties b/snake-and-ladder/src/main/resources/config.properties new file mode 100644 index 00000000..d30732cf --- /dev/null +++ b/snake-and-ladder/src/main/resources/config.properties @@ -0,0 +1 @@ +board.size=100 \ No newline at end of file diff --git a/snake-and-ladder/src/main/resources/snake&ladder.txt b/snake-and-ladder/src/main/resources/snake&ladder.txt new file mode 100644 index 00000000..5be01773 --- /dev/null +++ b/snake-and-ladder/src/main/resources/snake&ladder.txt @@ -0,0 +1,22 @@ +9 +62 5 +33 6 +49 9 +88 16 +41 20 +56 53 +98 64 +93 73 +95 75 +8 +2 37 +27 46 +10 32 +51 68 +61 79 +65 84 +71 91 +81 100 +2 +Gaurav +Sagar \ No newline at end of file diff --git a/snake-and-ladder/src/test/java/ApplicationTest.java b/snake-and-ladder/src/test/java/ApplicationTest.java new file mode 100644 index 00000000..11f4543b --- /dev/null +++ b/snake-and-ladder/src/test/java/ApplicationTest.java @@ -0,0 +1,2 @@ +public class ApplicationTest { +} diff --git a/snake-and-ladder/src/test/java/model/BoardTest.java b/snake-and-ladder/src/test/java/model/BoardTest.java new file mode 100644 index 00000000..d36fbfdf --- /dev/null +++ b/snake-and-ladder/src/test/java/model/BoardTest.java @@ -0,0 +1,37 @@ +package model; + +import in.aghorii.snakeandladder.model.Board; +import in.aghorii.snakeandladder.model.Ladder; +import in.aghorii.snakeandladder.model.Player; +import in.aghorii.snakeandladder.model.Snake; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class BoardTest { + + @Test + public void testBoard(){ + //Initialize + List snakes = new ArrayList<>(Collections.singletonList(new Snake(1, 2))); + List ladders = new ArrayList<>(Collections.singletonList(new Ladder(1, 2))); + List players = new ArrayList<>(Collections.singletonList(new Player("player 1"))); + + //Execute + Board board = new Board.BoardBuilder() + .boardSize(101) + .snakes(snakes) + .ladders(ladders) + .players(players) + .build(); + + //Assert + Assertions.assertEquals(board.getBoardSize(), 101); + Assertions.assertEquals(board.getSnakes().size(), 1); + Assertions.assertEquals(board.getPlayers().size(), 1); + Assertions.assertEquals(board.getPlayers().get(0).getName(), "player 1"); + } +} diff --git a/snake-and-ladder/src/test/java/service/BoardCreatorTest.java b/snake-and-ladder/src/test/java/service/BoardCreatorTest.java new file mode 100644 index 00000000..a8441f27 --- /dev/null +++ b/snake-and-ladder/src/test/java/service/BoardCreatorTest.java @@ -0,0 +1,44 @@ +package service; + +import in.aghorii.snakeandladder.model.Board; +import in.aghorii.snakeandladder.model.Ladder; +import in.aghorii.snakeandladder.model.Player; +import in.aghorii.snakeandladder.model.Snake; +import in.aghorii.snakeandladder.service.creator.BoardCreator; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class BoardCreatorTest { + + public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException { + BoardCreatorTest test = new BoardCreatorTest(); + + test.testBoardCreator(); + } + + private void testBoardCreator() throws NoSuchFieldException, IllegalAccessException { + //Initialize + BoardCreator boardCreator = new BoardCreator(); + + Field boardSizeField = BoardCreator.class.getDeclaredField("boardSize"); + boardSizeField.setAccessible(true); + boardSizeField.set(boardCreator, 100); + + List snakes = new ArrayList<>(Collections.singletonList(new Snake(1, 2))); + List ladders = new ArrayList<>(Collections.singletonList(new Ladder(1, 2))); + List players = new ArrayList<>(Collections.singletonList(new Player("player 1"))); + + //Execute + Board board = boardCreator.createBoard(snakes, ladders, players); + + //Assert + if (board.getPlayers() != null && !"player 1".equals(board.getPlayers().get(0).getName())) { + System.out.println("Test Failed"); + } else { + System.out.println("Test Passed"); + } + } +}