Mediator: Chat Room

Problem

Build a chat room. Commands: JOIN name (print joined, or error if the name is already in the room), LEAVE name (print left, or error if the name is not in the room) and SEND name message (the message is one word). SEND prints, for every other member in the order of joining, the text recipient got message from sender, joined with the two characters '; '. If nobody else is in the room it prints nobody. A sender that is not in the room gets error. Use the mediator pattern: users never talk to each other directly; the chat room delivers the messages.

Constraints

  • 1 <= lines <= 1000
  • names and messages are single words

Examples

Input

JOIN amit
JOIN bela
SEND amit hi

Output

joined
joined
bela got hi from amit

Solutions

Best approachTime O(n * members)Space O(members)

Without a mediator every user would need a reference to every other user (n * n links). With a mediator each user knows only the room. Join and leave change one list, and delivery rules live in one place.

Same code works in Java810172125Basic features only, so nothing changes between versions.
/*
 * Problem : Process lines.
 * Input   : Several command lines.
 * Output  : One result per command.
 * Approach: Room as the mediator.
 * Time    : O(n * members)
 * Space   : O(members)
 * Java    : 8 or newer.
 */
import java.util.Scanner;

public class Main {
        // Step 1: The room is the mediator. It knows all users, and users know only the room.
        static class ChatRoom {
            private final java.util.List<User> users = new java.util.ArrayList<User>();

            boolean join(User user) {
                if (find(user.name) != null) {
                    return false;
                }
                user.room = this;
                users.add(user);
                return true;
            }

            boolean leave(String name) {
                User user = find(name);
                return user != null && users.remove(user);
            }

            User find(String name) {
                for (User user : users) {
                    if (user.name.equals(name)) {
                        return user;
                    }
                }
                return null;
            }

            // Step 2: Delivery is the room's job. It calls receive() on every user except the sender.
            String deliver(User from, String message) {
                java.util.List<String> parts = new java.util.ArrayList<String>();
                for (User user : users) {
                    if (user != from) {
                        parts.add(user.receive(from.name, message));
                    }
                }
                return parts.isEmpty() ? "nobody" : String.join("; ", parts);
            }
        }

        static class User {
            final String name;
            ChatRoom room;

            User(String name) {
                this.name = name;
            }

            String receive(String sender, String message) {
                return name + " got " + message + " from " + sender;
            }
        }

    // This method solves the task. It receives the input and returns the answer.
    static String[] solve(String[] lines) {
        ChatRoom room = new ChatRoom();
        String[] output = new String[lines.length];
        for (int i = 0; i < lines.length; i++) {
            String[] part = lines[i].split(" ");
            if (part[0].equals("JOIN")) {
                output[i] = room.join(new User(part[1])) ? "joined" : "error";
            } else if (part[0].equals("LEAVE")) {
                output[i] = room.leave(part[1]) ? "left" : "error";
            } else {
                User sender = room.find(part[1]);
                output[i] = sender == null ? "error" : room.deliver(sender, part[2]);
            }
        }
        return output;
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        java.util.List<String> all = new java.util.ArrayList<>();
        while (scanner.hasNextLine()) {
            String line = scanner.nextLine().trim();
            if (!line.isEmpty()) {
                all.add(line);
            }
        }
        String[] lines = all.toArray(new String[0]);
        System.out.println(String.join("\n", solve(lines)));
    }
}
Hints (2)
  1. How many links does each user have?
  2. Who decides who gets a message?