Pages

Aquathon

/* The customary usage order of some frequently used modifiers:
 *
 * public / private
 * abstract
 * static
 * final
 *
 * Source: https://stackoverflow.com/questions/16731240/
 */

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

/**
 *  The Event class has the main method of a pedagogical program that
 *  demonstrates several of Java's object-oriented programming constructs.
 */
public class Event {
    public static void main(String[] args)
    {
        Aquathon race = new Aquathon();
        
        Person aquaman = new Person("Aquaman"),
               wonderWoman = new Person("Wonder Woman"),
               superman = new Person("Superman");
               
        Dog lassy = new Dog("Lassy"),
            scoobyDoo = new Dog("Scooby Doo");

        aquaman.swimTraining(8000);
        wonderWoman.runTraining(10000);
        lassy.runTraining(10000);

        Amphibian[] competitors =
        {
            superman,
            wonderWoman,
            aquaman,
            scoobyDoo,
            lassy
        };

        for (Amphibian winner : race.individualWinners(competitors))
            System.out.println("Champion: " + winner.toString());
    }
}
class Aquathon
{
    private double swimDistance;
    private double runDistance;

    public Aquathon() { this(0.62, 3.1); }
    public Aquathon(double swimMiles, double runMiles)
    {
        this.swimDistance = swimMiles;
        this.runDistance = runMiles;
    }
    public double finishTime(Swimmer swimmer, Runner runner)
    {
        double swimTime = this.swimDistance / swimmer.swimSpeed();
        double runTime = this.runDistance / runner.runSpeed();
        return swimTime + runTime;
    }
    public List<Amphibian> individualWinners(Amphibian[] competitors)
    {
        ArrayList<Amphibian> winners = new ArrayList<Amphibian>();
        Double fastestTime = 0.0;
        for (Amphibian athlete : competitors)
        {
            double athleteTime = finishTime(athlete, athlete);
            if (winners.size() == 0)
            {
                System.out.println("First winner: " + athlete.toString());
                System.out.println("Time: " + athleteTime);
                winners.add(athlete);
                fastestTime = athleteTime;
            }
            else
            {
                if (athleteTime == fastestTime)
                {
                    System.out.println("Yet another winner: " + athlete.toString());
                    winners.add(athlete);
                }
                else if (athleteTime < fastestTime)
                {
                    System.out.println("Previous fastest time: " + fastestTime);
                    System.out.println("New fastest time: " + athleteTime);
                    System.out.println("New winner: " + athlete.toString());
                    winners.clear();
                    winners.add(athlete);
                }
            }
        }
        return winners;
    }
}
/*************/
/* Functions */
/*************/

class Natural
{
    public static double ability()
    {
        return 0.75 + (Math.random() * 0.5);
    }
}

class Performance
{
    public static double result(double avg, double talent, double training)
    {
        final double MAX_TRAINING = 10000;
        final double MAX_IMPROVEMENT = 0.5;

        double nurture = 1 + training >= MAX_TRAINING ?
            MAX_IMPROVEMENT : MAX_IMPROVEMENT * training / MAX_TRAINING;

        return avg * talent * nurture;
    }
}

/**************/
/* Interfaces */
/**************/

interface Runner
{
    public double runSpeed();
    public void runTraining(double amount);
}

interface Swimmer
{
    public double swimSpeed();
    public void swimTraining(double amount);
}

interface Amphibian extends Runner, Swimmer
{
}
/********************/
/* Abstract Classes */
/********************/

abstract class Pedestrian
{
    private String name;
    
    public Pedestrian(String name) { this.name = name; }
    public String toString()
    {
        return name + " (" + numberOfLegs() + " legs)";
    }
    public abstract int numberOfLegs();
}

abstract class Quadruped extends Pedestrian {
    public Quadruped(String name) { super(name); }
    public int numberOfLegs()     { return 4; }
}

abstract class Biped extends Pedestrian {
    public Biped(String name) { super(name); }
    public int numberOfLegs() { return 2; }
}
/**
 * A Person is a Biped that can swim and run.
 */
class Person extends Biped implements Amphibian
{
    private static final double AVG_RUN_SPEED = 7;  // mph
    private static final double AVG_SWIM_SPEED = 2; // mph
    private double runTraining = 500;               // hours
    private double swimTraining = 1;                // hours
    private double runTalent = Natural.ability();
    private double swimTalent = Natural.ability();

    public Person(String name)           { super(name); }
    public void runTraining(double amt)  { this.runTraining = amt; }
    public void swimTraining(double amt) { this.swimTraining = amt; }
    public double runSpeed()
    {
        return Performance.result(Person.AVG_RUN_SPEED,
                                  this.runTalent,
                                  this.runTraining);
    }
    public double swimSpeed()
    {
        return Performance.result(Person.AVG_SWIM_SPEED,
                                  this.swimTalent,
                                  this.swimTraining);
    }
}
/**
 * A Dog is a Quadruped that can swim and run.
 */
class Dog extends Quadruped implements Amphibian
{
    private static final double AVG_RUN_SPEED = 15; // mph
    private static final double AVG_SWIM_SPEED = 1; // mph
    private double runTraining = 5000;              // hours
    private double swimTraining = 10;               // hours
    private double runTalent = Natural.ability();
    private double swimTalent = Natural.ability();

    public Dog(String name)              { super(name); }
    public void runTraining(double amt)  { this.runTraining = amt; }
    public void swimTraining(double amt) { this.swimTraining = amt; }
    public double runSpeed()
    {
        return Performance.result(Dog.AVG_RUN_SPEED,
                                  this.runTalent,
                                  this.runTraining);
    }
    public double swimSpeed()
    {
        return Performance.result(Dog.AVG_SWIM_SPEED,
                                  this.swimTalent,
                                  this.swimTraining);
    }
}
/**
 *  A Pig is a Quadruped that can run.
 */
class Pig extends Quadruped implements Runner
{
    private static final double AVG_RUN_SPEED = 6; // mph
    private double runTraining = 100; // hours
    private double runTalent = Natural.ability();

    public Pig()                         { this("Some Pig"); }
    public Pig(String name)              { super(name); }
    public void runTraining(double amt)  { this.runTraining = amt; }
    public double runSpeed()
    {
        return Performance.result(Pig.AVG_RUN_SPEED,
                                  this.runTalent,
                                  this.runTraining);
    }
}

/**
 *  A Shark can swim.
 */
class Shark implements Swimmer
{
    private static final double AVG_SWIM_SPEED = 20; // mph
    private double swimTraining = 10000;             // hours
    private double swimTalent = Natural.ability();

    public String toString()             { return "Shark"; }
    public void swimTraining(double amt) { this.swimTraining = amt; }
    public double swimSpeed()
    {
        return Performance.result(Shark.AVG_SWIM_SPEED,
                                  this.swimTalent,
                                  this.swimTraining);
    }
}