LMU ☀️ CMSI 3801
LANGUAGES AND AUTOMATA I
HOMEWORK #3 PARTIAL ANSWERS
Exercises.java
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.IntConsumer;
import java.util.function.Predicate;
import java.util.stream.IntStream;
import static java.util.stream.Collectors.toList;
import static java.lang.Integer.parseInt;

public interface Exercises {

    static List<Integer> change(int amount) {
        if (amount < 0) {
            throw new IllegalArgumentException("Amount cannot be negative");
        }
        var denominations = List.of(25, 10, 5, 1);
        var coins = new ArrayList<Integer>();
        for (var denomination : denominations) {
            coins.add(amount / denomination);
            amount %= denomination;
        }
        return List.copyOf(coins);
    }

    static String stretched(String s) {
        var codePoints = s.replaceAll("\\s+", "").codePoints();
        var count = 1;
        var builder = new StringBuilder();
        for (var codePoint : codePoints.toArray()) {
            builder.append(new String(Character.toChars(codePoint)).repeat(count++));
        }
        return builder.toString();
    }

    static void powers(int base, int limit, IntConsumer consumer) {
        for (int power = 1; power <= limit; power *= base) {
            consumer.accept(power);
        }
    }

    static IntStream powers(int base) {
        return IntStream.iterate(1, power -> power * base);
    }

    static String say() {
        return "";
    }

    static record Sayer(String phrase) {
        Sayer and(String word) {
            return new Sayer(phrase + ' ' + word);
        }

        String ok() {
            return phrase;
        }
    }

    static Sayer say(String word) {
        return new Sayer(word);
    }

    static Optional<String> findFirstThenLower(Predicate<String> p, List<String> strings) {
        return strings.stream()
                .filter(p)
                .findFirst()
                .map(String::toLowerCase);
    }

    static List<String> topTenScorers(Map<String, List<String>> stats) {
        record Player(String name, String team, int games, int points) {
            double ppg() {
                return (double) points / games;
            }
        }
        return stats.entrySet().stream()
                .flatMap(e -> e.getValue().stream().map(player -> player + "," + e.getKey()))
                .map(line -> line.split(","))
                .map(p -> new Player(p[0], p[3], parseInt(p[1]), parseInt(p[2])))
                .filter(p -> p.games >= 15)
                .sorted((p1, p2) -> Double.compare(p2.ppg(), p1.ppg()))
                .limit(10)
                .map(p -> String.format("%s|%.2f|%s", p.name(), p.ppg(), p.team()))
                .collect(toList());
    }
}
Quaternion.java
import java.util.List;

public record Quaternion(double a, double b, double c, double d) {

    public static final Quaternion ZERO = new Quaternion(0, 0, 0, 0);
    public static final Quaternion I = new Quaternion(0, 1, 0, 0);
    public static final Quaternion J = new Quaternion(0, 0, 1, 0);
    public static final Quaternion K = new Quaternion(0, 0, 0, 1);

    public Quaternion {
        if (Double.isNaN(a) || Double.isNaN(b) || Double.isNaN(c) || Double.isNaN(d)) {
            throw new IllegalArgumentException("Coefficients cannot be NaN");
        }
    }

    public Quaternion plus(Quaternion q) {
        return new Quaternion(a + q.a, b + q.b, c + q.c, d + q.d);
    }

    public Quaternion minus(Quaternion q) {
        return new Quaternion(a - q.a, b - q.b, c - q.c, d - q.d);
    }

    public Quaternion times(Quaternion q) {
        return new Quaternion(
                q.a * a - q.b * b - q.c * c - q.d * d,
                q.a * b + q.b * a - q.c * d + q.d * c,
                q.a * c + q.b * d + q.c * a - q.d * b,
                q.a * d - q.b * c + q.c * b + q.d * a);
    }

    public List<Double> coefficients() {
        return List.of(a, b, c, d);
    }
}