Skip to content
This repository was archived by the owner on May 18, 2022. It is now read-only.
Open
Show file tree
Hide file tree
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
Binary file added .DS_Store
Binary file not shown.
77 changes: 77 additions & 0 deletions Splitwise/Client.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package Designs.Splitwise;

// https://workat.tech/machine-coding/practice/splitwise-problem-0kp2yneec2q2

import Designs.Splitwise.machine.Machine;
import Designs.Splitwise.machine.Splitwise;
import Designs.Splitwise.model.User;
import Designs.Splitwise.modeselector.SplitModeSelector;
import Designs.Splitwise.modeselector.SplitTypes;
import Designs.Splitwise.parser.Parser;
import Designs.Splitwise.splitmodes.EqualSplitMode;
import Designs.Splitwise.splitmodes.ExactSplitMode;
import Designs.Splitwise.splitmodes.PercentSplitMode;

import java.util.HashMap;
import java.util.Map;

//You can create a few users in your main method. No need to take it as input.
//There will be 3 types of input:
//SplitTypes in the format: EXPENSE <user-id-of-person-who-paid> <no-of-users> <space-separated-list-of-users> <EQUAL/EXACT/PERCENT> <space-separated-values-in-case-of-non-equal>
//Show balances for all: SHOW
//Show balances for a single user: SHOW <user-id>

//SHOW
//SHOW u1
//EXPENSE u1 1000 4 u1 u2 u3 u4 EQUAL
//SHOW u4
//SHOW u1
//EXPENSE u1 1250 2 u2 u3 EXACT 370 880
//SHOW
//EXPENSE u4 1200 4 u1 u2 u3 u4 PERCENT 40 20 20 20
//SHOW u1
//SHOW
public class Client {
public static void main(String[] args) {
// onboard users in the machine
User u1 = new User("u1", "jack", "jack@gmail.com", 9289);
User u2 = new User("u2", "Tom", "tom@gmail.com", 9282);
User u3 = new User("u3", "kev", "kev@gmail.com", 9281);
User u4 = new User("u4", "rees", "rees@gmail.com", 9280);

Map<String, User> usersMap = new HashMap<>();
usersMap.put(u1.getUserId(), u1);
usersMap.put(u2.getUserId(), u2);
usersMap.put(u3.getUserId(), u3);
usersMap.put(u4.getUserId(), u4);

// initialise SplitModeSelector
SplitModeSelector splitModeSelector = new SplitModeSelector(
Map.of(SplitTypes.EQUAL, new EqualSplitMode(),
SplitTypes.EXACT, new ExactSplitMode(),
SplitTypes.PERCENT, new PercentSplitMode()
));

// Initialise Machine
Machine machine = new Splitwise(usersMap, splitModeSelector);

// Commands
String equalExpense = "EXPENSE u1 1000 4 u1 u2 u3 u4 EQUAL";
String exactExpense = "EXPENSE u1 1250 2 u2 u3 EXACT 370 880";
String percentExpense = "EXPENSE u4 1200 4 u1 u2 u3 u4 PERCENT 40 20 20 20";
String show = "SHOW";
String show_u1 = "SHOW u1";
String show_u4 = "SHOW u4";

// Input to Parser
Parser parser = new Parser(machine);
parser.parse(equalExpense);
parser.parse(show_u4);
parser.parse(show_u1);
parser.parse(exactExpense);
parser.parse(show);
parser.parse(percentExpense);
parser.parse(show_u1);
parser.parse(show);
}
}
9 changes: 9 additions & 0 deletions Splitwise/machine/Machine.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package Designs.Splitwise.machine;

public interface Machine {
void showAll();

void showBalanceFor(String userId);

void addExpense(String[] tokens);
}
43 changes: 43 additions & 0 deletions Splitwise/machine/Splitwise.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package Designs.Splitwise.machine;

import Designs.Splitwise.model.User;
import Designs.Splitwise.splitmodes.SplitMode;
import Designs.Splitwise.modeselector.SplitModeSelector;
import Designs.Splitwise.modeselector.SplitTypes;

import java.util.Map;

public class Splitwise implements Machine {
private Map<String, User> usersMap;
private SplitModeSelector modeSelector;

public Splitwise(Map<String, User> usersMap, SplitModeSelector modeSelector) {
this.usersMap = usersMap;
this.modeSelector = modeSelector;
}

@Override
public void showAll() {
for (Map.Entry<String, User> entry : usersMap.entrySet()) {
User user = entry.getValue();
user.showDebt();
}
}

@Override
public void showBalanceFor(String userId) {
User user = usersMap.get(userId);
if (user == null) System.out.println("User not found");
user.showDebt();
user.showLoan();
}

@Override
public void addExpense(String[] tokens) {
int userLength = Integer.parseInt(tokens[3]);
SplitTypes splitType = SplitTypes.valueOf(tokens[4 + userLength]);

SplitMode mode = modeSelector.select(splitType);
mode.addExpense(usersMap, tokens);
}
}
88 changes: 88 additions & 0 deletions Splitwise/model/User.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package Designs.Splitwise.model;

import java.util.HashMap;
import java.util.Map;

public class User {
private final String userId;
private final String name;
private final String email;
private final Integer mobileNumber;
private final Map<User, Double> debtMap;
private final Map<User, Double> loanMap;

public User(String userId, String name, String email, Integer mobileNumber) {
this.userId = userId;
this.name = name;
this.email = email;
this.mobileNumber = mobileNumber;
this.debtMap = new HashMap<>();
this.loanMap = new HashMap<>();
}

public String getUserId() {
return userId;
}

public String getName() {
return name;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof User)) return false;

User user = (User) o;

if (!userId.equals(user.userId)) return false;
if (!getName().equals(user.getName())) return false;
if (!email.equals(user.email)) return false;
return mobileNumber.equals(user.mobileNumber);
}

@Override
public int hashCode() {
int result = userId.hashCode();
result = 31 * result + getName().hashCode();
result = 31 * result + email.hashCode();
result = 31 * result + mobileNumber.hashCode();
return result;
}

public Double debtFrom(User user) {
return debtMap.getOrDefault(user, 0.0);
}

public Double loanGivenTo(User user) {
return loanMap.getOrDefault(user, 0.0);
}

public void addLoanFor(User user, Double balance) {
loanMap.put(user, balance);
}

public void addDebtFor(User user, Double balance) {
debtMap.put(user, balance);
}

public void removeDebtFor(User user) {
debtMap.remove(user);
}

public void removeLoanFor(User borrower) {
loanMap.remove(borrower);
}

public void showDebt() {
for (Map.Entry<User, Double> entry : debtMap.entrySet()) {
System.out.println(name + " owes " + entry.getKey().name + " : " + Math.abs(entry.getValue()));
}
}

public void showLoan() {
for (Map.Entry<User, Double> entry : loanMap.entrySet()) {
System.out.println(entry.getKey().name + " owes " + name + " : " + Math.abs(entry.getValue()));
}
}
}
17 changes: 17 additions & 0 deletions Splitwise/modeselector/SplitModeSelector.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package Designs.Splitwise.modeselector;

import Designs.Splitwise.splitmodes.SplitMode;

import java.util.Map;

public class SplitModeSelector {
private Map<SplitTypes, SplitMode> map;

public SplitModeSelector(Map<SplitTypes, SplitMode> map) {
this.map = map;
}

public SplitMode select(SplitTypes type) {
return map.get(type);
}
}
5 changes: 5 additions & 0 deletions Splitwise/modeselector/SplitTypes.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package Designs.Splitwise.modeselector;

public enum SplitTypes {
EQUAL, EXACT, PERCENT
}
24 changes: 24 additions & 0 deletions Splitwise/parser/Parser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package Designs.Splitwise.parser;

import Designs.Splitwise.machine.Machine;

public class Parser {
private final Machine machine;

public Parser(Machine machine) {
this.machine = machine;
}

public void parse(String cmd) {
String[] tokens = cmd.split(" ");
if (tokens[0].equals("SHOW")) {
if (tokens.length == 1) {
machine.showAll();
} else if (tokens.length == 2) {
machine.showBalanceFor(tokens[1]);
}
} else if (tokens[0].equals("EXPENSE")) {
machine.addExpense(tokens);
}
}
}
27 changes: 27 additions & 0 deletions Splitwise/splitmodes/EqualSplitMode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package Designs.Splitwise.splitmodes;

import Designs.Splitwise.model.User;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class EqualSplitMode extends SplitMode {

@Override
public void addExpense(Map<String, User> usersMap, String[] tokens) {
initialise(tokens, usersMap);

double equalShare = expenseToAdd / users.size();

for (User borrower : users) {
if (borrower == lender) continue;
// lender side
updateLenderPortfolio(lender, equalShare, borrower);

// borrower side
updateBorrowerPortfolio(lender, equalShare, borrower);
}
}

}
41 changes: 41 additions & 0 deletions Splitwise/splitmodes/ExactSplitMode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package Designs.Splitwise.splitmodes;

import Designs.Splitwise.model.User;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class ExactSplitMode extends SplitMode {

@Override
public void addExpense(Map<String, User> usersMap, String[] tokens) {
initialise(tokens, usersMap);

List<Double> expenseDistribution = populateExpenseDistribution(tokens);
boolean isValid = validate(expenseToAdd, expenseDistribution);
if (!isValid) {
System.out.println("Invalid input");
return;
}

int j = 0;
for (User borrower : users) {
double exactShare = expenseDistribution.get(j++);
if (borrower == lender) continue;
// lender side
updateLenderPortfolio(lender, exactShare, borrower);

// borrower side
updateBorrowerPortfolio(lender, exactShare, borrower);
}
}

private boolean validate(double expenseToAdd, List<Double> expenseDistribution) {
double sum = 0;
for (Double d : expenseDistribution) {
sum += d;
}
return expenseToAdd == sum;
}
}
43 changes: 43 additions & 0 deletions Splitwise/splitmodes/PercentSplitMode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package Designs.Splitwise.splitmodes;

import Designs.Splitwise.model.User;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class PercentSplitMode extends SplitMode {

@Override
public void addExpense(Map<String, User> usersMap, String[] tokens) {
initialise(tokens, usersMap);

List<Double> expenseDistribution = populateExpenseDistribution(tokens);
boolean isValid = validate(expenseDistribution);
if (!isValid) {
System.out.println("Invalid input");
return;
}

int j = 0;
for (User borrower : users) {
double percent = expenseDistribution.get(j++);
double exactShare = percent / 100 * expenseToAdd;
if (borrower == lender) continue;
// lender side
updateLenderPortfolio(lender, exactShare, borrower);

// borrower side
updateBorrowerPortfolio(lender, exactShare, borrower);
}
}

private boolean validate(List<Double> expenseDistribution) {
double sum = 0;
for (Double d : expenseDistribution) {
sum += d;
}
return sum == 100.0;
}

}
Loading