LMU ☀️ CMSI 3801
LANGUAGES AND AUTOMATA I
HOMEWORK #5 Due: 2024-12-06

Learning Objectives

With this assignment you will demonstrate:

Readings and Videos

Please:

Instructions

Work in teams of 1 to 4 students.

Continue working on the repository you forked in Homework #1. Please remember that you should have only one official (graded) forked repository per group.

There are no unit tests supplied for this assignment, but we will run your submissions and eyeball the results for correctness. As specified in the README file for the homework template repository linked above, your grade depends not only on (1) all tests passing, but a significant portion will be based on (2) following instructions, (3) maintaining a clean repository, (4) code hygiene, and (5) following all formatting, indentation, naming, and styling conventions of the programming language.

To submit your work, choose one and only one team member to submit to BrightSpace a single text file containing (1) the names of all team members and (2) the URL of your private forked repository. Your homework submission will be the state of your repository on your main branch, at 18:00 in the America/Los Angeles time zone on the due date.

Code

Implement the following simulation in Go (that’s right—there’s only one language for this assignment): Ten customers (Ani, Bai, Cat, Dao, Eve, Fay, Gus, Hua, Iza, and Jai) make several visits to a restaurant with three cooks (Remy, Colette, and Linguini) and only one waiter. As each customer arrives, they try to place an order with the busy waiter, who can only hold 3 outstanding orders at a time. The waiter takes the order to a free cook (if any) who prepares the meal, which takes a random amount of time (5000-10000 ms). The cook personally delivers the meal to the customer. If it takes too long (7000 ms) for a customer to get their order placed (after all, the waiter can’t hold that many orders at a time), they leave the restaurant and come back later (between 2500 and 5000 ms). It takes between 1000 and 2000 ms to eat a meal. When a customer eats five meals, they go home. Only after all customers have gone home, the restaurant shuts down.

Because it may help a bit, here is a solution in Java:

Restaurant.java
import java.util.List;
import java.time.LocalDateTime;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;

public class Restaurant {

    // Java's built-in logging utility is a bit of overkill for this example.
    private static void log(Object... args) {
        var strings = List.of(args).stream().map(Object::toString).toList();
        System.out.println(LocalDateTime.now() + " " + String.join(" ", strings));
    }

    // A little utility that simulates performing a task for a random duration.
    // For example, calling doAction(10, "Remy", "is cooking") will compute a
    // random number of millisecs between 5000 and 10000, log "Remy is cooking",
    // and sleep the current goroutine for that much time.
    private static void doAction(int seconds, Object... action) {
        log(action);
        try {
            var randomMillis = 500 * seconds + 
                    ThreadLocalRandom.current().nextInt(500 * seconds);
            Thread.sleep(randomMillis);
        } catch (InterruptedException e) {
            // Restore interrupted status and continue
            Thread.currentThread().interrupt();
        }
    }

    // An order for a meal is placed by a customer and is taken by a cook.
    // When the meal is finished, the cook will send the finished meal through
    // the reply channel. Each order has a unique id, safely incremented using
    // an atomic counter.
    static class Order {
        static final AtomicLong nextId = new AtomicLong(0);
        final long id;
        final String customer;
        final CompletableFuture<Order> reply;
        String preparedBy;

        Order(String customer) {
            this.id = nextId.incrementAndGet();
            this.customer = customer;
            this.reply = new CompletableFuture<>();
        }
    }

    // The waiter is represented by a channel of orders, which in Java is
    // represented as a BlockingQueue. The waiter will take orders from
    // customers and send them to the cook. The cook will then send the
    // prepared meal back to the waiter. To simulate a waiter being busy,
    // the waiter channel has a buffer capacity of 3 orders.
    private static final BlockingQueue<Order> waiter = new LinkedBlockingQueue<>(3);

    // A cook spends their time fetching orders from the order channel,
    // cooking the requested meal, and sending the meal back through the
    // order's reply channel. The cook function is designed to be run on a
    // Java virtual thread.
    public static void cook(String name) {
        log(name, "starting work");
        while (true) {
            try {
                // We want to get the order with a blocking call
                var order = waiter.take();
                doAction(10, name, "cooking order", order.id, "for", order.customer);
                order.preparedBy = name;
                // Completing the future sends the cooked order back to the customer
                order.reply.complete(order);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            }
        }
    }

    // A customer eats five meals and then goes home. Each time they enter the
    // restaurant, they place an order with the waiter. If the waiter is too
    // busy, the customer will wait for 5 seconds before abandoning the order.
    // If the order does get placed, then they will wait as long as necessary
    // for the meal to be cooked and delivered.
    public static void customer(String name, CountDownLatch latch) {
        try {
            for (var mealsEaten = 0; mealsEaten < 5; ) {
                var order = new Order(name);
                log(name, "placed order", order.id);

                try {
                    // Wait 7 seconds for the waiter to take the order
                    if (waiter.offer(order, 7, TimeUnit.SECONDS)) {
                        // Wait indefinitely for the meal to be cooked
                        var meal = order.reply.get();
                        // Eat for up to 2 seconds
                        doAction(2, name, "eating cooked order", meal.id,
                                "prepared by", meal.preparedBy);
                        mealsEaten++;
                    } else {
                        doAction(5, name, "waiting too long, abandoning order", order.id);
                    }
                } catch (InterruptedException | ExecutionException e) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
            log(name, "going home");
        } finally {
            latch.countDown();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        var customers = List.of(
            "Ani", "Bai", "Cat", "Dao", "Eve", "Fay", "Gus", "Hua", "Iza", "Jai");

        // All threads will be virtual threads
        ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
        executor.execute(() -> cook("Remy"));
        executor.execute(() -> cook("Colette"));
        executor.execute(() -> cook("Linguini"));

        // Need a latch in order to wait for all customers to finish
        CountDownLatch latch = new CountDownLatch(customers.size());
        for (String customer : customers) {
            executor.execute(() -> customer(customer, latch));
        }
        latch.await();

        // Cleanup nicely
        log("Restaurant closing");
        executor.shutdown();
    }
}

Here are your requirements for translating to Go:

Here is an example output when using log.Println in Go:

2024/08/24 22:41:21 Linguini starting work
2024/08/24 22:41:21 Bai placed order 1
2024/08/24 22:41:21 Cat placed order 3
2024/08/24 22:41:21 Linguini cooking order 1 for Bai
2024/08/24 22:41:21 Iza placed order 4
2024/08/24 22:41:21 Ani placed order 2
2024/08/24 22:41:21 Remy starting work
2024/08/24 22:41:21 Remy cooking order 3 for Cat
2024/08/24 22:41:21 Gus placed order 6
2024/08/24 22:41:21 Fay placed order 5
2024/08/24 22:41:21 Jai placed order 7
2024/08/24 22:41:21 Hua placed order 8
2024/08/24 22:41:21 Colette starting work
2024/08/24 22:41:21 Colette cooking order 4 for Iza
2024/08/24 22:41:21 Eve placed order 10
2024/08/24 22:41:21 Dao placed order 9
2024/08/24 22:41:27 Colette cooking order 2 for Ani
2024/08/24 22:41:27 Iza eating cooked order 4 prepared by Colette
2024/08/24 22:41:28 Iza placed order 11
2024/08/24 22:41:28 Dao waiting too long, abandoning order 9
2024/08/24 22:41:28 Hua waiting too long, abandoning order 8
2024/08/24 22:41:28 Eve waiting too long, abandoning order 10
2024/08/24 22:41:28 Linguini cooking order 6 for Gus
2024/08/24 22:41:28 Bai eating cooked order 1 prepared by Linguini
2024/08/24 22:41:30 Bai placed order 12
2024/08/24 22:41:30 Remy cooking order 5 for Fay
2024/08/24 22:41:30 Cat eating cooked order 3 prepared by Remy
2024/08/24 22:41:31 Eve placed order 13
2024/08/24 22:41:32 Cat placed order 14
2024/08/24 22:41:33 Dao placed order 15
2024/08/24 22:41:33 Hua placed order 16
2024/08/24 22:41:34 Colette cooking order 7 for Jai
2024/08/24 22:41:34 Ani eating cooked order 2 prepared by Colette
2024/08/24 22:41:36 Ani placed order 17
2024/08/24 22:41:36 Linguini cooking order 11 for Iza
2024/08/24 22:41:36 Gus eating cooked order 6 prepared by Linguini
2024/08/24 22:41:37 Remy cooking order 12 for Bai
2024/08/24 22:41:37 Fay eating cooked order 5 prepared by Remy
2024/08/24 22:41:38 Gus placed order 18
2024/08/24 22:41:39 Fay placed order 19
2024/08/24 22:41:40 Hua waiting too long, abandoning order 16
2024/08/24 22:41:41 Colette cooking order 13 for Eve
2024/08/24 22:41:41 Jai eating cooked order 7 prepared by Colette
2024/08/24 22:41:42 Jai placed order 20
2024/08/24 22:41:42 Linguini cooking order 14 for Cat
2024/08/24 22:41:42 Iza eating cooked order 11 prepared by Linguini
2024/08/24 22:41:43 Iza placed order 21
2024/08/24 22:41:44 Hua placed order 22
2024/08/24 22:41:46 Remy cooking order 15 for Dao
2024/08/24 22:41:46 Bai eating cooked order 12 prepared by Remy
2024/08/24 22:41:46 Colette cooking order 17 for Ani
2024/08/24 22:41:46 Eve eating cooked order 13 prepared by Colette
2024/08/24 22:41:47 Bai placed order 23
2024/08/24 22:41:48 Eve placed order 24
2024/08/24 22:41:50 Iza waiting too long, abandoning order 21
2024/08/24 22:41:51 Hua waiting too long, abandoning order 22
2024/08/24 22:41:52 Linguini cooking order 18 for Gus
2024/08/24 22:41:52 Cat eating cooked order 14 prepared by Linguini
2024/08/24 22:41:53 Cat placed order 25
2024/08/24 22:41:54 Remy cooking order 19 for Fay
2024/08/24 22:41:54 Dao eating cooked order 15 prepared by Remy
2024/08/24 22:41:54 Hua placed order 26
2024/08/24 22:41:54 Iza placed order 27
2024/08/24 22:41:55 Colette cooking order 20 for Jai
2024/08/24 22:41:55 Ani eating cooked order 17 prepared by Colette
2024/08/24 22:41:55 Dao placed order 28
2024/08/24 22:41:57 Ani placed order 29
2024/08/24 22:41:58 Linguini cooking order 23 for Bai
2024/08/24 22:41:58 Gus eating cooked order 18 prepared by Linguini
2024/08/24 22:41:59 Gus placed order 30
2024/08/24 22:42:01 Iza waiting too long, abandoning order 27
2024/08/24 22:42:02 Remy cooking order 24 for Eve
2024/08/24 22:42:02 Fay eating cooked order 19 prepared by Remy
2024/08/24 22:42:03 Fay placed order 31
2024/08/24 22:42:03 Colette cooking order 25 for Cat
2024/08/24 22:42:03 Jai eating cooked order 20 prepared by Colette
2024/08/24 22:42:04 Iza placed order 32
2024/08/24 22:42:05 Jai placed order 33
2024/08/24 22:42:06 Gus waiting too long, abandoning order 30
2024/08/24 22:42:07 Remy cooking order 26 for Hua
2024/08/24 22:42:07 Eve eating cooked order 24 prepared by Remy
2024/08/24 22:42:08 Linguini cooking order 28 for Dao
2024/08/24 22:42:08 Bai eating cooked order 23 prepared by Linguini
2024/08/24 22:42:08 Eve placed order 34
2024/08/24 22:42:09 Bai placed order 35
2024/08/24 22:42:10 Gus placed order 36
2024/08/24 22:42:12 Jai waiting too long, abandoning order 33
2024/08/24 22:42:12 Colette cooking order 29 for Ani
2024/08/24 22:42:12 Cat eating cooked order 25 prepared by Colette
2024/08/24 22:42:14 Linguini cooking order 31 for Fay
2024/08/24 22:42:14 Dao eating cooked order 28 prepared by Linguini
2024/08/24 22:42:14 Cat placed order 37
2024/08/24 22:42:15 Jai placed order 38
2024/08/24 22:42:15 Dao placed order 39
2024/08/24 22:42:15 Remy cooking order 32 for Iza
2024/08/24 22:42:15 Hua eating cooked order 26 prepared by Remy
2024/08/24 22:42:17 Hua placed order 40
2024/08/24 22:42:20 Colette cooking order 34 for Eve
2024/08/24 22:42:20 Ani eating cooked order 29 prepared by Colette
2024/08/24 22:42:21 Ani placed order 41
2024/08/24 22:42:21 Linguini cooking order 35 for Bai
2024/08/24 22:42:21 Fay eating cooked order 31 prepared by Linguini
2024/08/24 22:42:22 Dao waiting too long, abandoning order 39
2024/08/24 22:42:23 Fay placed order 42
2024/08/24 22:42:24 Hua waiting too long, abandoning order 40
2024/08/24 22:42:25 Remy cooking order 36 for Gus
2024/08/24 22:42:25 Iza eating cooked order 32 prepared by Remy
2024/08/24 22:42:26 Iza placed order 43
2024/08/24 22:42:27 Dao placed order 44
2024/08/24 22:42:27 Hua placed order 45
2024/08/24 22:42:30 Colette cooking order 37 for Cat
2024/08/24 22:42:30 Eve eating cooked order 34 prepared by Colette
2024/08/24 22:42:31 Eve placed order 46
2024/08/24 22:42:31 Linguini cooking order 38 for Jai
2024/08/24 22:42:31 Bai eating cooked order 35 prepared by Linguini
2024/08/24 22:42:33 Bai placed order 47
2024/08/24 22:42:34 Dao waiting too long, abandoning order 44
2024/08/24 22:42:34 Hua waiting too long, abandoning order 45
2024/08/24 22:42:34 Remy cooking order 41 for Ani
2024/08/24 22:42:34 Gus eating cooked order 36 prepared by Remy
2024/08/24 22:42:35 Gus placed order 48
2024/08/24 22:42:37 Colette cooking order 42 for Fay
2024/08/24 22:42:37 Cat eating cooked order 37 prepared by Colette
2024/08/24 22:42:38 Cat placed order 49
2024/08/24 22:42:38 Dao placed order 50
2024/08/24 22:42:39 Hua placed order 51
2024/08/24 22:42:40 Remy cooking order 43 for Iza
2024/08/24 22:42:40 Ani eating cooked order 41 prepared by Remy
2024/08/24 22:42:40 Linguini cooking order 46 for Eve
2024/08/24 22:42:40 Jai eating cooked order 38 prepared by Linguini
2024/08/24 22:42:41 Ani placed order 52
2024/08/24 22:42:41 Jai placed order 53
2024/08/24 22:42:44 Colette cooking order 47 for Bai
2024/08/24 22:42:44 Fay eating cooked order 42 prepared by Colette
2024/08/24 22:42:46 Fay placed order 54
2024/08/24 22:42:46 Hua waiting too long, abandoning order 51
2024/08/24 22:42:48 Linguini cooking order 48 for Gus
2024/08/24 22:42:48 Eve eating cooked order 46 prepared by Linguini
2024/08/24 22:42:48 Jai waiting too long, abandoning order 53
2024/08/24 22:42:49 Remy cooking order 49 for Cat
2024/08/24 22:42:49 Iza eating cooked order 43 prepared by Remy
2024/08/24 22:42:49 Hua placed order 55
2024/08/24 22:42:50 Eve placed order 56
2024/08/24 22:42:50 Iza placed order 57
2024/08/24 22:42:51 Jai placed order 58
2024/08/24 22:42:51 Colette cooking order 50 for Dao
2024/08/24 22:42:51 Bai eating cooked order 47 prepared by Colette
2024/08/24 22:42:52 Bai going home
2024/08/24 22:42:53 Linguini cooking order 52 for Ani
2024/08/24 22:42:53 Gus eating cooked order 48 prepared by Linguini
2024/08/24 22:42:54 Remy cooking order 54 for Fay
2024/08/24 22:42:54 Cat eating cooked order 49 prepared by Remy
2024/08/24 22:42:55 Gus placed order 59
2024/08/24 22:42:56 Cat going home
2024/08/24 22:42:58 Jai waiting too long, abandoning order 58
2024/08/24 22:43:01 Linguini cooking order 55 for Hua
2024/08/24 22:43:01 Ani eating cooked order 52 prepared by Linguini
2024/08/24 22:43:01 Jai placed order 60
2024/08/24 22:43:01 Colette cooking order 56 for Eve
2024/08/24 22:43:01 Dao eating cooked order 50 prepared by Colette
2024/08/24 22:43:02 Remy cooking order 57 for Iza
2024/08/24 22:43:02 Fay eating cooked order 54 prepared by Remy
2024/08/24 22:43:02 Dao placed order 61
2024/08/24 22:43:03 Ani going home
2024/08/24 22:43:03 Fay going home
2024/08/24 22:43:06 Colette cooking order 59 for Gus
2024/08/24 22:43:06 Eve eating cooked order 56 prepared by Colette
2024/08/24 22:43:07 Linguini cooking order 60 for Jai
2024/08/24 22:43:07 Hua eating cooked order 55 prepared by Linguini
2024/08/24 22:43:08 Eve going home
2024/08/24 22:43:09 Hua placed order 62
2024/08/24 22:43:10 Remy cooking order 61 for Dao
2024/08/24 22:43:10 Iza eating cooked order 57 prepared by Remy
2024/08/24 22:43:12 Colette cooking order 62 for Hua
2024/08/24 22:43:12 Gus eating cooked order 59 prepared by Colette
2024/08/24 22:43:12 Iza going home
2024/08/24 22:43:13 Gus going home
2024/08/24 22:43:14 Jai eating cooked order 60 prepared by Linguini
2024/08/24 22:43:16 Jai placed order 63
2024/08/24 22:43:16 Linguini cooking order 63 for Jai
2024/08/24 22:43:18 Dao eating cooked order 61 prepared by Remy
2024/08/24 22:43:20 Dao placed order 64
2024/08/24 22:43:20 Remy cooking order 64 for Dao
2024/08/24 22:43:21 Hua eating cooked order 62 prepared by Colette
2024/08/24 22:43:22 Jai eating cooked order 63 prepared by Linguini
2024/08/24 22:43:23 Hua placed order 65
2024/08/24 22:43:23 Colette cooking order 65 for Hua
2024/08/24 22:43:24 Jai going home
2024/08/24 22:43:26 Dao eating cooked order 64 prepared by Remy
2024/08/24 22:43:28 Dao going home
2024/08/24 22:43:31 Hua eating cooked order 65 prepared by Colette
2024/08/24 22:43:32 Hua placed order 66
2024/08/24 22:43:32 Linguini cooking order 66 for Hua
2024/08/24 22:43:38 Hua eating cooked order 66 prepared by Linguini
2024/08/24 22:43:39 Hua going home
2024/08/24 22:43:39 Restaurant closing

Grading

You will be awarded up to 75 points for correctness, that is, (1) each customer eats exactly five meals, (2) the simulation is free of deadlocks, livelocks, and race conditions, (3) the simulation is accurate in that a customer is not eating two meals at a time, etc., and (4) everything shuts down normally (i.e., there are no resource leaks and no premature termination). The other 25 points are earned by precisely following all instructions, writing the logged messages with the format shown above, writing code that is built according to each language’s conventions, keeping a clean repository, etc. Your feedback will be in the form of deductions for such things as:

This list is not exhaustive, but should help in getting you used to paying attention to your submissions and taking pride in your work. Note that most code editors have plugins that will auto-format your code and even look for suspicious coding practices. You are strongly encouraged to use them.