diff --git a/enums/AlarmPoints.java b/enums/AlarmPoints.java new file mode 100644 index 00000000..03b3bdfb --- /dev/null +++ b/enums/AlarmPoints.java @@ -0,0 +1,7 @@ +//: enums/AlarmPoints.java +// ©2015 MindView LLC: see Copyright.txt +package enums; +public enum AlarmPoints { + STAIR1, STAIR2, LOBBY, OFFICE1, OFFICE2, OFFICE3, + OFFICE4, BATHROOM, UTILITY, KITCHEN +} ///:~ diff --git a/enums/BigEnumSet.java b/enums/BigEnumSet.java new file mode 100644 index 00000000..9f113e33 --- /dev/null +++ b/enums/BigEnumSet.java @@ -0,0 +1,19 @@ +//: enums/BigEnumSet.java +// ©2015 MindView LLC: see Copyright.txt +import java.util.*; + +public class BigEnumSet { + enum Big { A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, + A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, + A22, A23, A24, A25, A26, A27, A28, A29, A30, A31, A32, + A33, A34, A35, A36, A37, A38, A39, A40, A41, A42, A43, + A44, A45, A46, A47, A48, A49, A50, A51, A52, A53, A54, + A55, A56, A57, A58, A59, A60, A61, A62, A63, A64, A65, + A66, A67, A68, A69, A70, A71, A72, A73, A74, A75 } + public static void main(String[] args) { + EnumSet bigEnumSet = EnumSet.allOf(Big.class); + System.out.println(bigEnumSet); + } +} /* Output: +[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25, A26, A27, A28, A29, A30, A31, A32, A33, A34, A35, A36, A37, A38, A39, A40, A41, A42, A43, A44, A45, A46, A47, A48, A49, A50, A51, A52, A53, A54, A55, A56, A57, A58, A59, A60, A61, A62, A63, A64, A65, A66, A67, A68, A69, A70, A71, A72, A73, A74, A75] +*///:~ diff --git a/enums/Burrito.java b/enums/Burrito.java new file mode 100644 index 00000000..8793d6bd --- /dev/null +++ b/enums/Burrito.java @@ -0,0 +1,20 @@ +//: enums/Burrito.java +// ©2015 MindView LLC: see Copyright.txt +package enums; +import static enums.Spiciness.*; + +public class Burrito { + Spiciness degree; + public Burrito(Spiciness degree) { this.degree = degree;} + @Override + public String toString() { return "Burrito is "+ degree;} + public static void main(String[] args) { + System.out.println(new Burrito(NOT)); + System.out.println(new Burrito(MEDIUM)); + System.out.println(new Burrito(HOT)); + } +} /* Output: +Burrito is NOT +Burrito is MEDIUM +Burrito is HOT +*///:~ diff --git a/enums/CarWash.java b/enums/CarWash.java new file mode 100644 index 00000000..5548c376 --- /dev/null +++ b/enums/CarWash.java @@ -0,0 +1,68 @@ +//: enums/CarWash.java +// ©2015 MindView LLC: see Copyright.txt +import java.util.*; +import static net.mindview.util.Print.*; + +public class CarWash { + public enum Cycle { + UNDERBODY { + @Override + void action() { print("Spraying the underbody"); } + }, + WHEELWASH { + @Override + void action() { print("Washing the wheels"); } + }, + PREWASH { + @Override + void action() { print("Loosening the dirt"); } + }, + BASIC { + @Override + void action() { print("The basic wash"); } + }, + HOTWAX { + @Override + void action() { print("Applying hot wax"); } + }, + RINSE { + @Override + void action() { print("Rinsing"); } + }, + BLOWDRY { + @Override + void action() { print("Blowing dry"); } + }; + abstract void action(); + } + EnumSet cycles = + EnumSet.of(Cycle.BASIC, Cycle.RINSE); + public void add(Cycle cycle) { cycles.add(cycle); } + public void washCar() { + for(Cycle c : cycles) + c.action(); + } + @Override + public String toString() { return cycles.toString(); } + public static void main(String[] args) { + CarWash wash = new CarWash(); + print(wash); + wash.washCar(); + // Order of addition is unimportant: + wash.add(Cycle.BLOWDRY); + wash.add(Cycle.BLOWDRY); // Duplicates ignored + wash.add(Cycle.RINSE); + wash.add(Cycle.HOTWAX); + print(wash); + wash.washCar(); + } +} /* Output: +[BASIC, RINSE] +The basic wash +Rinsing +[BASIC, HOTWAX, RINSE, BLOWDRY] +The basic wash +Applying hot wax +Rinsing +Blowing dry +*///:~ diff --git a/enums/Competitor.java b/enums/Competitor.java new file mode 100644 index 00000000..8a24bc2b --- /dev/null +++ b/enums/Competitor.java @@ -0,0 +1,8 @@ +//: enums/Competitor.java +// ©2015 MindView LLC: see Copyright.txt +// Switching one enum on another. +package enums; + +public interface Competitor> { + Outcome compete(T competitor); +} ///:~ diff --git a/enums/ConstantSpecificMethod.java b/enums/ConstantSpecificMethod.java new file mode 100644 index 00000000..e855173b --- /dev/null +++ b/enums/ConstantSpecificMethod.java @@ -0,0 +1,31 @@ +//: enums/ConstantSpecificMethod.java +// ©2015 MindView LLC: see Copyright.txt +import java.util.*; +import java.text.*; + +public enum ConstantSpecificMethod { + DATE_TIME { + @Override + String getInfo() { + return + DateFormat.getDateInstance().format(new Date()); + } + }, + CLASSPATH { + @Override + String getInfo() { + return System.getenv("CLASSPATH"); + } + }, + VERSION { + @Override + String getInfo() { + return System.getProperty("java.version"); + } + }; + abstract String getInfo(); + public static void main(String[] args) { + for(ConstantSpecificMethod csm : values()) + System.out.println(csm.getInfo()); + } +} /* (Execute to see output) *///:~ diff --git a/enums/EnumClass.java b/enums/EnumClass.java new file mode 100644 index 00000000..1f60c235 --- /dev/null +++ b/enums/EnumClass.java @@ -0,0 +1,44 @@ +//: enums/EnumClass.java +// ©2015 MindView LLC: see Copyright.txt +// Capabilities of the Enum class +import static net.mindview.util.Print.*; + +enum Shrubbery { GROUND, CRAWLING, HANGING } + +public class EnumClass { + public static void main(String[] args) { + for(Shrubbery s : Shrubbery.values()) { + print(s + " ordinal: " + s.ordinal()); + printnb(s.compareTo(Shrubbery.CRAWLING) + " "); + printnb(s.equals(Shrubbery.CRAWLING) + " "); + print(s == Shrubbery.CRAWLING); + print(s.getDeclaringClass()); + print(s.name()); + print("----------------------"); + } + // Produce an enum value from a string name: + for(String s : "HANGING CRAWLING GROUND".split(" ")) { + Shrubbery shrub = Enum.valueOf(Shrubbery.class, s); + print(shrub); + } + } +} /* Output: +GROUND ordinal: 0 +-1 false false +class Shrubbery +GROUND +---------------------- +CRAWLING ordinal: 1 +0 true true +class Shrubbery +CRAWLING +---------------------- +HANGING ordinal: 2 +1 false false +class Shrubbery +HANGING +---------------------- +HANGING +CRAWLING +GROUND +*///:~ diff --git a/enums/EnumMaps.java b/enums/EnumMaps.java new file mode 100644 index 00000000..7c9f68e9 --- /dev/null +++ b/enums/EnumMaps.java @@ -0,0 +1,31 @@ +//: enums/EnumMaps.java +// ©2015 MindView LLC: see Copyright.txt +// Basics of EnumMaps. +package enums; +import java.util.*; +import static enums.AlarmPoints.*; +import static net.mindview.util.Print.*; + +interface Command { void action(); } + +public class EnumMaps { + public static void main(String[] args) { + EnumMap em = + new EnumMap<>(AlarmPoints.class); + em.put(KITCHEN, () -> print("Kitchen fire!")); + em.put(BATHROOM, () -> print("Bathroom alert!")); + for(Map.Entry e : em.entrySet()) { + printnb(e.getKey() + ": "); + e.getValue().action(); + } + try { // If there's no value for a particular key: + em.get(UTILITY).action(); + } catch(Exception e) { + print("Expected: " + e); + } + } +} /* Output: +BATHROOM: Bathroom alert! +KITCHEN: Kitchen fire! +Expected: java.lang.NullPointerException +*///:~ diff --git a/enums/EnumSets.java b/enums/EnumSets.java new file mode 100644 index 00000000..89a4c64a --- /dev/null +++ b/enums/EnumSets.java @@ -0,0 +1,31 @@ +//: enums/EnumSets.java +// ©2015 MindView LLC: see Copyright.txt +// Operations on EnumSets +package enums; +import java.util.*; +import static enums.AlarmPoints.*; +import static net.mindview.util.Print.*; + +public class EnumSets { + public static void main(String[] args) { + EnumSet points = + EnumSet.noneOf(AlarmPoints.class); // Empty set + points.add(BATHROOM); + print(points); + points.addAll(EnumSet.of(STAIR1, STAIR2, KITCHEN)); + print(points); + points = EnumSet.allOf(AlarmPoints.class); + points.removeAll(EnumSet.of(STAIR1, STAIR2, KITCHEN)); + print(points); + points.removeAll(EnumSet.range(OFFICE1, OFFICE4)); + print(points); + points = EnumSet.complementOf(points); + print(points); + } +} /* Output: +[BATHROOM] +[STAIR1, STAIR2, BATHROOM, KITCHEN] +[LOBBY, OFFICE1, OFFICE2, OFFICE3, OFFICE4, BATHROOM, UTILITY] +[LOBBY, BATHROOM, UTILITY] +[STAIR1, STAIR2, OFFICE1, OFFICE2, OFFICE3, OFFICE4, KITCHEN] +*///:~ diff --git a/enums/Input.java b/enums/Input.java new file mode 100644 index 00000000..f8e3a2fd --- /dev/null +++ b/enums/Input.java @@ -0,0 +1,29 @@ +//: enums/Input.java +// ©2015 MindView LLC: see Copyright.txt +import java.util.*; + +public enum Input { + NICKEL(5), DIME(10), QUARTER(25), DOLLAR(100), + TOOTHPASTE(200), CHIPS(75), SODA(100), SOAP(50), + ABORT_TRANSACTION { + @Override + public int amount() { // Disallow + throw new RuntimeException("ABORT.amount()"); + } + }, + STOP { // This must be the last instance. + @Override + public int amount() { // Disallow + throw new RuntimeException("SHUT_DOWN.amount()"); + } + }; + int value; // In cents + Input(int value) { this.value = value; } + Input() {} + int amount() { return value; }; // In cents + static Random rand = new Random(47); + public static Input randomSelection() { + // Don't include STOP: + return values()[rand.nextInt(values().length - 1)]; + } +} ///:~ diff --git a/enums/NonEnum.java b/enums/NonEnum.java new file mode 100644 index 00000000..af23bac7 --- /dev/null +++ b/enums/NonEnum.java @@ -0,0 +1,16 @@ +//: enums/NonEnum.java +// ©2015 MindView LLC: see Copyright.txt + +public class NonEnum { + public static void main(String[] args) { + Class intClass = Integer.class; + try { + for(Object en : intClass.getEnumConstants()) + System.out.println(en); + } catch(Exception e) { + System.out.println("Expected: " + e); + } + } +} /* Output: +Expected: java.lang.NullPointerException +*///:~ diff --git a/enums/NotClasses.java b/enums/NotClasses.java new file mode 100644 index 00000000..be45c585 --- /dev/null +++ b/enums/NotClasses.java @@ -0,0 +1,27 @@ +//: enums/NotClasses.java +// ©2015 MindView LLC: see Copyright.txt +// {Exec: javap -c LikeClasses} +import static net.mindview.util.Print.*; + +enum LikeClasses { + WINKEN {@Override + void behavior() { print("Behavior1"); } }, + BLINKEN {@Override + void behavior() { print("Behavior2"); } }, + NOD {@Override + void behavior() { print("Behavior3"); } }; + abstract void behavior(); +} + +public class NotClasses { + // void f1(LikeClasses.WINKEN instance) {} // Nope +} /* Output: (First 7 Lines) +Compiled from "NotClasses.java" +abstract class LikeClasses extends java.lang.Enum{ +public static final LikeClasses WINKEN; + +public static final LikeClasses BLINKEN; + +public static final LikeClasses NOD; +... +*///:~ diff --git a/enums/Outcome.java b/enums/Outcome.java new file mode 100644 index 00000000..ed483344 --- /dev/null +++ b/enums/Outcome.java @@ -0,0 +1,4 @@ +//: enums/Outcome.java +// ©2015 MindView LLC: see Copyright.txt +package enums; +public enum Outcome { WIN, LOSE, DRAW } ///:~ diff --git a/enums/OverrideConstantSpecific.java b/enums/OverrideConstantSpecific.java new file mode 100644 index 00000000..9a7dd870 --- /dev/null +++ b/enums/OverrideConstantSpecific.java @@ -0,0 +1,22 @@ +//: enums/OverrideConstantSpecific.java +// ©2015 MindView LLC: see Copyright.txt +import static net.mindview.util.Print.*; + +public enum OverrideConstantSpecific { + NUT, BOLT, + WASHER { + @Override + void f() { print("Overridden method"); } + }; + void f() { print("default behavior"); } + public static void main(String[] args) { + for(OverrideConstantSpecific ocs : values()) { + printnb(ocs + ": "); + ocs.f(); + } + } +} /* Output: +NUT: default behavior +BOLT: default behavior +WASHER: Overridden method +*///:~ diff --git a/enums/OzWitch.java b/enums/OzWitch.java new file mode 100644 index 00000000..dab24ad5 --- /dev/null +++ b/enums/OzWitch.java @@ -0,0 +1,28 @@ +//: enums/OzWitch.java +// ©2015 MindView LLC: see Copyright.txt +// The witches in the land of Oz. +import static net.mindview.util.Print.*; + +public enum OzWitch { + // Instances must be defined first, before methods: + WEST("Miss Gulch, aka the Wicked Witch of the West"), + NORTH("Glinda, the Good Witch of the North"), + EAST("Wicked Witch of the East, wearer of the Ruby " + + "Slippers, crushed by Dorothy's house"), + SOUTH("Good by inference, but missing"); + private String description; + // Constructor must be package or private access: + private OzWitch(String description) { + this.description = description; + } + public String getDescription() { return description; } + public static void main(String[] args) { + for(OzWitch witch : OzWitch.values()) + print(witch + ": " + witch.getDescription()); + } +} /* Output: +WEST: Miss Gulch, aka the Wicked Witch of the West +NORTH: Glinda, the Good Witch of the North +EAST: Wicked Witch of the East, wearer of the Ruby Slippers, crushed by Dorothy's house +SOUTH: Good by inference, but missing +*///:~ diff --git a/enums/PostOffice.java b/enums/PostOffice.java new file mode 100644 index 00000000..9942242b --- /dev/null +++ b/enums/PostOffice.java @@ -0,0 +1,162 @@ +//: enums/PostOffice.java +// ©2015 MindView LLC: see Copyright.txt +// Modeling a post office. +import java.util.*; +import net.mindview.util.*; +import static net.mindview.util.Print.*; + +class Mail { + // The NO's lower the probability of random selection: + enum GeneralDelivery {YES,NO1,NO2,NO3,NO4,NO5} + enum Scannability {UNSCANNABLE,YES1,YES2,YES3,YES4} + enum Readability {ILLEGIBLE,YES1,YES2,YES3,YES4} + enum Address {INCORRECT,OK1,OK2,OK3,OK4,OK5,OK6} + enum ReturnAddress {MISSING,OK1,OK2,OK3,OK4,OK5} + GeneralDelivery generalDelivery; + Scannability scannability; + Readability readability; + Address address; + ReturnAddress returnAddress; + static long counter = 0; + long id = counter++; + @Override + public String toString() { return "Mail " + id; } + public String details() { + return toString() + + ", General Delivery: " + generalDelivery + + ", Address Scanability: " + scannability + + ", Address Readability: " + readability + + ", Address Address: " + address + + ", Return address: " + returnAddress; + } + // Generate test Mail: + public static Mail randomMail() { + Mail m = new Mail(); + m.generalDelivery= Enums.random(GeneralDelivery.class); + m.scannability = Enums.random(Scannability.class); + m.readability = Enums.random(Readability.class); + m.address = Enums.random(Address.class); + m.returnAddress = Enums.random(ReturnAddress.class); + return m; + } + public static Iterable generator(final int count) { + return new Iterable() { + int n = count; + @Override + public Iterator iterator() { + return new Iterator() { + @Override + public boolean hasNext() { return n-- > 0; } + @Override + public Mail next() { return randomMail(); } + @Override + public void remove() { // Not implemented + throw new UnsupportedOperationException(); + } + }; + } + }; + } +} + +public class PostOffice { + enum MailHandler { + GENERAL_DELIVERY { + @Override + boolean handle(Mail m) { + switch(m.generalDelivery) { + case YES: + print("Using general delivery for " + m); + return true; + default: return false; + } + } + }, + MACHINE_SCAN { + @Override + boolean handle(Mail m) { + switch(m.scannability) { + case UNSCANNABLE: return false; + default: + switch(m.address) { + case INCORRECT: return false; + default: + print("Delivering "+ m + " automatically"); + return true; + } + } + } + }, + VISUAL_INSPECTION { + @Override + boolean handle(Mail m) { + switch(m.readability) { + case ILLEGIBLE: return false; + default: + switch(m.address) { + case INCORRECT: return false; + default: + print("Delivering " + m + " normally"); + return true; + } + } + } + }, + RETURN_TO_SENDER { + @Override + boolean handle(Mail m) { + switch(m.returnAddress) { + case MISSING: return false; + default: + print("Returning " + m + " to sender"); + return true; + } + } + }; + abstract boolean handle(Mail m); + } + static void handle(Mail m) { + for(MailHandler handler : MailHandler.values()) + if(handler.handle(m)) + return; + print(m + " is a dead letter"); + } + public static void main(String[] args) { + for(Mail mail : Mail.generator(10)) { + print(mail.details()); + handle(mail); + print("*****"); + } + } +} /* Output: +Mail 0, General Delivery: NO2, Address Scanability: UNSCANNABLE, Address Readability: YES3, Address Address: OK1, Return address: OK1 +Delivering Mail 0 normally +***** +Mail 1, General Delivery: NO5, Address Scanability: YES3, Address Readability: ILLEGIBLE, Address Address: OK5, Return address: OK1 +Delivering Mail 1 automatically +***** +Mail 2, General Delivery: YES, Address Scanability: YES3, Address Readability: YES1, Address Address: OK1, Return address: OK5 +Using general delivery for Mail 2 +***** +Mail 3, General Delivery: NO4, Address Scanability: YES3, Address Readability: YES1, Address Address: INCORRECT, Return address: OK4 +Returning Mail 3 to sender +***** +Mail 4, General Delivery: NO4, Address Scanability: UNSCANNABLE, Address Readability: YES1, Address Address: INCORRECT, Return address: OK2 +Returning Mail 4 to sender +***** +Mail 5, General Delivery: NO3, Address Scanability: YES1, Address Readability: ILLEGIBLE, Address Address: OK4, Return address: OK2 +Delivering Mail 5 automatically +***** +Mail 6, General Delivery: YES, Address Scanability: YES4, Address Readability: ILLEGIBLE, Address Address: OK4, Return address: OK4 +Using general delivery for Mail 6 +***** +Mail 7, General Delivery: YES, Address Scanability: YES3, Address Readability: YES4, Address Address: OK2, Return address: MISSING +Using general delivery for Mail 7 +***** +Mail 8, General Delivery: NO3, Address Scanability: YES1, Address Readability: YES3, Address Address: INCORRECT, Return address: MISSING +Mail 8 is a dead letter +***** +Mail 9, General Delivery: NO1, Address Scanability: UNSCANNABLE, Address Readability: YES2, Address Address: OK1, Return address: OK4 +Delivering Mail 9 normally +***** +*///:~ diff --git a/enums/RandomTest.java b/enums/RandomTest.java new file mode 100644 index 00000000..2ed0fd56 --- /dev/null +++ b/enums/RandomTest.java @@ -0,0 +1,15 @@ +//: enums/RandomTest.java +// ©2015 MindView LLC: see Copyright.txt +import net.mindview.util.*; + +enum Activity { SITTING, LYING, STANDING, HOPPING, + RUNNING, DODGING, JUMPING, FALLING, FLYING } + +public class RandomTest { + public static void main(String[] args) { + for(int i = 0; i < 20; i++) + System.out.print(Enums.random(Activity.class) + " "); + } +} /* Output: +STANDING FLYING RUNNING STANDING RUNNING STANDING LYING DODGING SITTING RUNNING HOPPING HOPPING HOPPING RUNNING STANDING LYING FALLING RUNNING FLYING LYING +*///:~ diff --git a/enums/Reflection.java b/enums/Reflection.java new file mode 100644 index 00000000..479039d2 --- /dev/null +++ b/enums/Reflection.java @@ -0,0 +1,59 @@ +//: enums/Reflection.java +// ©2015 MindView LLC: see Copyright.txt +// Analyzing enums using reflection. +import java.lang.reflect.*; +import java.util.*; +import net.mindview.util.*; +import static net.mindview.util.Print.*; + +enum Explore { HERE, THERE } + +public class Reflection { + public static Set analyze(Class enumClass) { + print("----- Analyzing " + enumClass + " -----"); + print("Interfaces:"); + for(Type t : enumClass.getGenericInterfaces()) + print(t); + print("Base: " + enumClass.getSuperclass()); + print("Methods: "); + Set methods = new TreeSet<>(); + for(Method m : enumClass.getMethods()) + methods.add(m.getName()); + print(methods); + return methods; + } + public static void main(String[] args) { + Set exploreMethods = analyze(Explore.class); + Set enumMethods = analyze(Enum.class); + print("Explore.containsAll(Enum)? " + + exploreMethods.containsAll(enumMethods)); + printnb("Explore.removeAll(Enum): "); + exploreMethods.removeAll(enumMethods); + print(exploreMethods); + // Decompile the code for the enum: + OSExecute.command("javap Explore"); + } +} /* Output: +----- Analyzing class Explore ----- +Interfaces: +Base: class java.lang.Enum +Methods: +[compareTo, equals, getClass, getDeclaringClass, hashCode, name, notify, notifyAll, ordinal, toString, valueOf, values, wait] +----- Analyzing class java.lang.Enum ----- +Interfaces: +java.lang.Comparable +interface java.io.Serializable +Base: class java.lang.Object +Methods: +[compareTo, equals, getClass, getDeclaringClass, hashCode, name, notify, notifyAll, ordinal, toString, valueOf, wait] +Explore.containsAll(Enum)? true +Explore.removeAll(Enum): [values] +Compiled from "Reflection.java" +final class Explore extends java.lang.Enum{ + public static final Explore HERE; + public static final Explore THERE; + public static Explore[] values(); + public static Explore valueOf(java.lang.String); + static {}; +} +*///:~ diff --git a/enums/RoShamBo.java b/enums/RoShamBo.java new file mode 100644 index 00000000..d8f2a89f --- /dev/null +++ b/enums/RoShamBo.java @@ -0,0 +1,19 @@ +//: enums/RoShamBo.java +// ©2015 MindView LLC: see Copyright.txt +// Common tools for RoShamBo examples. +package enums; +import net.mindview.util.*; + +public class RoShamBo { + public static > + void match(T a, T b) { + System.out.println( + a + " vs. " + b + ": " + a.compete(b)); + } + public static & Competitor> + void play(Class rsbClass, int size) { + for(int i = 0; i < size; i++) + match( + Enums.random(rsbClass),Enums.random(rsbClass)); + } +} ///:~ diff --git a/enums/RoShamBo1.java b/enums/RoShamBo1.java new file mode 100644 index 00000000..a204d34a --- /dev/null +++ b/enums/RoShamBo1.java @@ -0,0 +1,94 @@ +//: enums/RoShamBo1.java +// ©2015 MindView LLC: see Copyright.txt +// Demonstration of multiple dispatching. +package enums; +import java.util.*; +import static enums.Outcome.*; + +interface Item { + Outcome compete(Item it); + Outcome eval(Paper p); + Outcome eval(Scissors s); + Outcome eval(Rock r); +} + +class Paper implements Item { + @Override + public Outcome compete(Item it) { return it.eval(this); } + @Override + public Outcome eval(Paper p) { return DRAW; } + @Override + public Outcome eval(Scissors s) { return WIN; } + @Override + public Outcome eval(Rock r) { return LOSE; } + @Override + public String toString() { return "Paper"; } +} + +class Scissors implements Item { + @Override + public Outcome compete(Item it) { return it.eval(this); } + @Override + public Outcome eval(Paper p) { return LOSE; } + @Override + public Outcome eval(Scissors s) { return DRAW; } + @Override + public Outcome eval(Rock r) { return WIN; } + @Override + public String toString() { return "Scissors"; } +} + +class Rock implements Item { + @Override + public Outcome compete(Item it) { return it.eval(this); } + @Override + public Outcome eval(Paper p) { return WIN; } + @Override + public Outcome eval(Scissors s) { return LOSE; } + @Override + public Outcome eval(Rock r) { return DRAW; } + @Override + public String toString() { return "Rock"; } +} + +public class RoShamBo1 { + static final int SIZE = 20; + private static Random rand = new Random(47); + public static Item newItem() { + switch(rand.nextInt(3)) { + default: + case 0: return new Scissors(); + case 1: return new Paper(); + case 2: return new Rock(); + } + } + public static void match(Item a, Item b) { + System.out.println( + a + " vs. " + b + ": " + a.compete(b)); + } + public static void main(String[] args) { + for(int i = 0; i < SIZE; i++) + match(newItem(), newItem()); + } +} /* Output: +Rock vs. Rock: DRAW +Paper vs. Rock: WIN +Paper vs. Rock: WIN +Paper vs. Rock: WIN +Scissors vs. Paper: WIN +Scissors vs. Scissors: DRAW +Scissors vs. Paper: WIN +Rock vs. Paper: LOSE +Paper vs. Paper: DRAW +Rock vs. Paper: LOSE +Paper vs. Scissors: LOSE +Paper vs. Scissors: LOSE +Rock vs. Scissors: WIN +Rock vs. Paper: LOSE +Paper vs. Rock: WIN +Scissors vs. Paper: WIN +Paper vs. Scissors: LOSE +Paper vs. Scissors: LOSE +Paper vs. Scissors: LOSE +Paper vs. Scissors: LOSE +*///:~ diff --git a/enums/RoShamBo2.java b/enums/RoShamBo2.java new file mode 100644 index 00000000..250237e6 --- /dev/null +++ b/enums/RoShamBo2.java @@ -0,0 +1,50 @@ +//: enums/RoShamBo2.java +// ©2015 MindView LLC: see Copyright.txt +// Switching one enum on another. +package enums; +import static enums.Outcome.*; + +public enum RoShamBo2 implements Competitor { + PAPER(DRAW, LOSE, WIN), + SCISSORS(WIN, DRAW, LOSE), + ROCK(LOSE, WIN, DRAW); + private Outcome vPAPER, vSCISSORS, vROCK; + RoShamBo2(Outcome paper,Outcome scissors,Outcome rock) { + this.vPAPER = paper; + this.vSCISSORS = scissors; + this.vROCK = rock; + } + @Override + public Outcome compete(RoShamBo2 it) { + switch(it) { + default: + case PAPER: return vPAPER; + case SCISSORS: return vSCISSORS; + case ROCK: return vROCK; + } + } + public static void main(String[] args) { + RoShamBo.play(RoShamBo2.class, 20); + } +} /* Output: +ROCK vs. ROCK: DRAW +SCISSORS vs. ROCK: LOSE +SCISSORS vs. ROCK: LOSE +SCISSORS vs. ROCK: LOSE +PAPER vs. SCISSORS: LOSE +PAPER vs. PAPER: DRAW +PAPER vs. SCISSORS: LOSE +ROCK vs. SCISSORS: WIN +SCISSORS vs. SCISSORS: DRAW +ROCK vs. SCISSORS: WIN +SCISSORS vs. PAPER: WIN +SCISSORS vs. PAPER: WIN +ROCK vs. PAPER: LOSE +ROCK vs. SCISSORS: WIN +SCISSORS vs. ROCK: LOSE +PAPER vs. SCISSORS: LOSE +SCISSORS vs. PAPER: WIN +SCISSORS vs. PAPER: WIN +SCISSORS vs. PAPER: WIN +SCISSORS vs. PAPER: WIN +*///:~ diff --git a/enums/RoShamBo3.java b/enums/RoShamBo3.java new file mode 100644 index 00000000..59112184 --- /dev/null +++ b/enums/RoShamBo3.java @@ -0,0 +1,46 @@ +//: enums/RoShamBo3.java +// ©2015 MindView LLC: see Copyright.txt +// Using constant-specific methods. +package enums; +import static enums.Outcome.*; + +public enum RoShamBo3 implements Competitor { + PAPER { + @Override + public Outcome compete(RoShamBo3 it) { + switch(it) { + default: // To placate the compiler + case PAPER: return DRAW; + case SCISSORS: return LOSE; + case ROCK: return WIN; + } + } + }, + SCISSORS { + @Override + public Outcome compete(RoShamBo3 it) { + switch(it) { + default: + case PAPER: return WIN; + case SCISSORS: return DRAW; + case ROCK: return LOSE; + } + } + }, + ROCK { + @Override + public Outcome compete(RoShamBo3 it) { + switch(it) { + default: + case PAPER: return LOSE; + case SCISSORS: return WIN; + case ROCK: return DRAW; + } + } + }; + @Override + public abstract Outcome compete(RoShamBo3 it); + public static void main(String[] args) { + RoShamBo.play(RoShamBo3.class, 20); + } +} /* Same output as RoShamBo2.java *///:~ diff --git a/enums/RoShamBo4.java b/enums/RoShamBo4.java new file mode 100644 index 00000000..5c28d56d --- /dev/null +++ b/enums/RoShamBo4.java @@ -0,0 +1,32 @@ +//: enums/RoShamBo4.java +// ©2015 MindView LLC: see Copyright.txt +package enums; + +public enum RoShamBo4 implements Competitor { + ROCK { + @Override + public Outcome compete(RoShamBo4 opponent) { + return compete(SCISSORS, opponent); + } + }, + SCISSORS { + @Override + public Outcome compete(RoShamBo4 opponent) { + return compete(PAPER, opponent); + } + }, + PAPER { + @Override + public Outcome compete(RoShamBo4 opponent) { + return compete(ROCK, opponent); + } + }; + Outcome compete(RoShamBo4 loser, RoShamBo4 opponent) { + return ((opponent == this) ? Outcome.DRAW + : ((opponent == loser) ? Outcome.WIN + : Outcome.LOSE)); + } + public static void main(String[] args) { + RoShamBo.play(RoShamBo4.class, 20); + } +} /* Same output as RoShamBo2.java *///:~ diff --git a/enums/RoShamBo5.java b/enums/RoShamBo5.java new file mode 100644 index 00000000..4c22d5ba --- /dev/null +++ b/enums/RoShamBo5.java @@ -0,0 +1,34 @@ +//: enums/RoShamBo5.java +// ©2015 MindView LLC: see Copyright.txt +// Multiple dispatching using an EnumMap of EnumMaps. +package enums; +import java.util.*; +import static enums.Outcome.*; + +enum RoShamBo5 implements Competitor { + PAPER, SCISSORS, ROCK; + static EnumMap> + table = new EnumMap<>(RoShamBo5.class); + static { + for(RoShamBo5 it : RoShamBo5.values()) + table.put(it, new EnumMap<>(RoShamBo5.class)); + initRow(PAPER, DRAW, LOSE, WIN); + initRow(SCISSORS, WIN, DRAW, LOSE); + initRow(ROCK, LOSE, WIN, DRAW); + } + static void initRow(RoShamBo5 it, + Outcome vPAPER, Outcome vSCISSORS, Outcome vROCK) { + EnumMap row = + RoShamBo5.table.get(it); + row.put(RoShamBo5.PAPER, vPAPER); + row.put(RoShamBo5.SCISSORS, vSCISSORS); + row.put(RoShamBo5.ROCK, vROCK); + } + @Override + public Outcome compete(RoShamBo5 it) { + return table.get(this).get(it); + } + public static void main(String[] args) { + RoShamBo.play(RoShamBo5.class, 20); + } +} /* Same output as RoShamBo2.java *///:~ diff --git a/enums/RoShamBo6.java b/enums/RoShamBo6.java new file mode 100644 index 00000000..a5b2cafa --- /dev/null +++ b/enums/RoShamBo6.java @@ -0,0 +1,21 @@ +//: enums/RoShamBo6.java +// ©2015 MindView LLC: see Copyright.txt +// Enums using "tables" instead of multiple dispatch. +package enums; +import static enums.Outcome.*; + +enum RoShamBo6 implements Competitor { + PAPER, SCISSORS, ROCK; + private static Outcome[][] table = { + { DRAW, LOSE, WIN }, // PAPER + { WIN, DRAW, LOSE }, // SCISSORS + { LOSE, WIN, DRAW }, // ROCK + }; + @Override + public Outcome compete(RoShamBo6 other) { + return table[this.ordinal()][other.ordinal()]; + } + public static void main(String[] args) { + RoShamBo.play(RoShamBo6.class, 20); + } +} ///:~ diff --git a/enums/SecurityCategory.java b/enums/SecurityCategory.java new file mode 100644 index 00000000..87537be5 --- /dev/null +++ b/enums/SecurityCategory.java @@ -0,0 +1,38 @@ +//: enums/SecurityCategory.java +// ©2015 MindView LLC: see Copyright.txt +// More succinct subcategorization of enums. +import net.mindview.util.*; + +enum SecurityCategory { + STOCK(Security.Stock.class), BOND(Security.Bond.class); + Security[] values; + SecurityCategory(Class kind) { + values = kind.getEnumConstants(); + } + interface Security { + enum Stock implements Security { SHORT, LONG, MARGIN } + enum Bond implements Security { MUNICIPAL, JUNK } + } + public Security randomSelection() { + return Enums.random(values); + } + public static void main(String[] args) { + for(int i = 0; i < 10; i++) { + SecurityCategory category = + Enums.random(SecurityCategory.class); + System.out.println(category + ": " + + category.randomSelection()); + } + } +} /* Output: +BOND: MUNICIPAL +BOND: MUNICIPAL +STOCK: MARGIN +STOCK: MARGIN +BOND: JUNK +STOCK: SHORT +STOCK: LONG +STOCK: LONG +BOND: MUNICIPAL +BOND: JUNK +*///:~ diff --git a/enums/SpaceShip.java b/enums/SpaceShip.java new file mode 100644 index 00000000..64f12b8a --- /dev/null +++ b/enums/SpaceShip.java @@ -0,0 +1,23 @@ +//: enums/SpaceShip.java +// ©2015 MindView LLC: see Copyright.txt +public enum SpaceShip { + SCOUT, CARGO, TRANSPORT, CRUISER, BATTLESHIP, MOTHERSHIP; + @Override + public String toString() { + String id = name(); + String lower = id.substring(1).toLowerCase(); + return id.charAt(0) + lower; + } + public static void main(String[] args) { + for(SpaceShip s : values()) { + System.out.println(s); + } + } +} /* Output: +Scout +Cargo +Transport +Cruiser +Battleship +Mothership +*///:~ diff --git a/enums/Spiciness.java b/enums/Spiciness.java new file mode 100644 index 00000000..7a60201a --- /dev/null +++ b/enums/Spiciness.java @@ -0,0 +1,7 @@ +//: enums/Spiciness.java +// ©2015 MindView LLC: see Copyright.txt +package enums; + +public enum Spiciness { + NOT, MILD, MEDIUM, HOT, FLAMING +} ///:~ diff --git a/enums/TrafficLight.java b/enums/TrafficLight.java new file mode 100644 index 00000000..303cb1b4 --- /dev/null +++ b/enums/TrafficLight.java @@ -0,0 +1,42 @@ +//: enums/TrafficLight.java +// ©2015 MindView LLC: see Copyright.txt +// Enums in switch statements. +import static net.mindview.util.Print.*; + +// Define an enum type: +enum Signal { GREEN, YELLOW, RED, } + +public class TrafficLight { + Signal color = Signal.RED; + public void change() { + switch(color) { + // Note that you don't have to say Signal.RED + // in the case statement: + case RED: color = Signal.GREEN; + break; + case GREEN: color = Signal.YELLOW; + break; + case YELLOW: color = Signal.RED; + break; + } + } + @Override + public String toString() { + return "The traffic light is " + color; + } + public static void main(String[] args) { + TrafficLight t = new TrafficLight(); + for(int i = 0; i < 7; i++) { + print(t); + t.change(); + } + } +} /* Output: +The traffic light is RED +The traffic light is GREEN +The traffic light is YELLOW +The traffic light is RED +The traffic light is GREEN +The traffic light is YELLOW +The traffic light is RED +*///:~ diff --git a/enums/UpcastEnum.java b/enums/UpcastEnum.java new file mode 100644 index 00000000..fada1708 --- /dev/null +++ b/enums/UpcastEnum.java @@ -0,0 +1,18 @@ +//: enums/UpcastEnum.java +// ©2015 MindView LLC: see Copyright.txt +// No values() method if you upcast an enum + +enum Search { HITHER, YON } + +public class UpcastEnum { + public static void main(String[] args) { + Search[] vals = Search.values(); + Enum e = Search.HITHER; // Upcast + // e.values(); // No values() in Enum + for(Enum en : e.getClass().getEnumConstants()) + System.out.println(en); + } +} /* Output: +HITHER +YON +*///:~ diff --git a/enums/VendingMachine.java b/enums/VendingMachine.java new file mode 100644 index 00000000..7c9d2a23 --- /dev/null +++ b/enums/VendingMachine.java @@ -0,0 +1,165 @@ +//: enums/VendingMachine.java +// ©2015 MindView LLC: see Copyright.txt +// {Args: VendingMachineInput.txt} +import java.util.*; +import net.mindview.util.*; +import static net.mindview.util.Print.*; + +enum Category { + MONEY(Input.NICKEL, Input.DIME, + Input.QUARTER, Input.DOLLAR), + ITEM_SELECTION(Input.TOOTHPASTE, Input.CHIPS, + Input.SODA, Input.SOAP), + QUIT_TRANSACTION(Input.ABORT_TRANSACTION), + SHUT_DOWN(Input.STOP); + private Input[] values; + Category(Input... types) { values = types; } + private static EnumMap categories = + new EnumMap<>(Input.class); + static { + for(Category c : Category.class.getEnumConstants()) + for(Input type : c.values) + categories.put(type, c); + } + public static Category categorize(Input input) { + return categories.get(input); + } +} + +public class VendingMachine { + private static State state = State.RESTING; + private static int amount = 0; + private static Input selection = null; + enum StateDuration { TRANSIENT } // Tagging enum + enum State { + RESTING { + @Override + void next(Input input) { + switch(Category.categorize(input)) { + case MONEY: + amount += input.amount(); + state = ADDING_MONEY; + break; + case SHUT_DOWN: + state = TERMINAL; + default: + } + } + }, + ADDING_MONEY { + @Override + void next(Input input) { + switch(Category.categorize(input)) { + case MONEY: + amount += input.amount(); + break; + case ITEM_SELECTION: + selection = input; + if(amount < selection.amount()) + print("Insufficient money for " + selection); + else state = DISPENSING; + break; + case QUIT_TRANSACTION: + state = GIVING_CHANGE; + break; + case SHUT_DOWN: + state = TERMINAL; + default: + } + } + }, + DISPENSING(StateDuration.TRANSIENT) { + @Override + void next() { + print("here is your " + selection); + amount -= selection.amount(); + state = GIVING_CHANGE; + } + }, + GIVING_CHANGE(StateDuration.TRANSIENT) { + @Override + void next() { + if(amount > 0) { + print("Your change: " + amount); + amount = 0; + } + state = RESTING; + } + }, + TERMINAL {@Override + void output() { print("Halted"); } }; + private boolean isTransient = false; + State() {} + State(StateDuration trans) { isTransient = true; } + void next(Input input) { + throw new RuntimeException("Only call " + + "next(Input input) for non-transient states"); + } + void next() { + throw new RuntimeException("Only call next() for " + + "StateDuration.TRANSIENT states"); + } + void output() { print(amount); } + } + static void run(Generator gen) { + while(state != State.TERMINAL) { + state.next(gen.next()); + while(state.isTransient) + state.next(); + state.output(); + } + } + public static void main(String[] args) { + Generator gen = new RandomInputGenerator(); + if(args.length == 1) + gen = new FileInputGenerator(args[0]); + run(gen); + } +} + +// For a basic sanity check: +class RandomInputGenerator implements Generator { + @Override + public Input next() { return Input.randomSelection(); } +} + +// Create Inputs from a file of ';'-separated strings: +class FileInputGenerator implements Generator { + private Iterator input; + public FileInputGenerator(String fileName) { + // Skip the comment line in the input file: + input = new TextFile(fileName, ";").listIterator(1); + } + @Override + public Input next() { + if(!input.hasNext()) + return null; + return Enum.valueOf(Input.class, input.next().trim()); + } +} /* Output: +25 +50 +75 +here is your CHIPS +0 +100 +200 +here is your TOOTHPASTE +0 +25 +35 +Your change: 35 +0 +25 +35 +Insufficient money for SODA +35 +60 +70 +75 +Insufficient money for SODA +75 +Your change: 75 +0 +Halted +*///:~ diff --git a/enums/VendingMachineInput.txt b/enums/VendingMachineInput.txt new file mode 100644 index 00000000..7dd1354e --- /dev/null +++ b/enums/VendingMachineInput.txt @@ -0,0 +1,9 @@ +//: enums/VendingMachineInput.txt +QUARTER; QUARTER; QUARTER; CHIPS; +DOLLAR; DOLLAR; TOOTHPASTE; +QUARTER; DIME; ABORT_TRANSACTION; +QUARTER; DIME; SODA; +QUARTER; DIME; NICKEL; SODA; +ABORT_TRANSACTION; +STOP; +///:~ diff --git a/enums/build.xml b/enums/build.xml new file mode 100644 index 00000000..96614583 --- /dev/null +++ b/enums/build.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/enums/cartoons/EnumImplementation.java b/enums/cartoons/EnumImplementation.java new file mode 100644 index 00000000..a521c1e5 --- /dev/null +++ b/enums/cartoons/EnumImplementation.java @@ -0,0 +1,30 @@ +//: enums/cartoons/EnumImplementation.java +// ©2015 MindView LLC: see Copyright.txt +// An enum can implement an interface +package enums.cartoons; +import java.util.*; +import net.mindview.util.*; + +enum CartoonCharacter +implements Generator { + SLAPPY, SPANKY, PUNCHY, SILLY, BOUNCY, NUTTY, BOB; + private Random rand = new Random(47); + @Override + public CartoonCharacter next() { + return values()[rand.nextInt(values().length)]; + } +} + +public class EnumImplementation { + public static void printNext(Generator rg) { + System.out.print(rg.next() + ", "); + } + public static void main(String[] args) { + // Choose any instance: + CartoonCharacter cc = CartoonCharacter.BOB; + for(int i = 0; i < 10; i++) + printNext(cc); + } +} /* Output: +BOB, PUNCHY, BOB, SPANKY, NUTTY, PUNCHY, SLAPPY, NUTTY, NUTTY, SLAPPY, +*///:~ diff --git a/enums/menu/Course.java b/enums/menu/Course.java new file mode 100644 index 00000000..dbe537ac --- /dev/null +++ b/enums/menu/Course.java @@ -0,0 +1,18 @@ +//: enums/menu/Course.java +// ©2015 MindView LLC: see Copyright.txt +package enums.menu; +import net.mindview.util.*; + +public enum Course { + APPETIZER(Food.Appetizer.class), + MAINCOURSE(Food.MainCourse.class), + DESSERT(Food.Dessert.class), + COFFEE(Food.Coffee.class); + private Food[] values; + private Course(Class kind) { + values = kind.getEnumConstants(); + } + public Food randomSelection() { + return Enums.random(values); + } +} ///:~ diff --git a/enums/menu/Food.java b/enums/menu/Food.java new file mode 100644 index 00000000..cf961fac --- /dev/null +++ b/enums/menu/Food.java @@ -0,0 +1,22 @@ +//: enums/menu/Food.java +// ©2015 MindView LLC: see Copyright.txt +// Subcategorization of enums within interfaces. +package enums.menu; + +public interface Food { + enum Appetizer implements Food { + SALAD, SOUP, SPRING_ROLLS; + } + enum MainCourse implements Food { + LASAGNE, BURRITO, PAD_THAI, + LENTILS, HUMMOUS, VINDALOO; + } + enum Dessert implements Food { + TIRAMISU, GELATO, BLACK_FOREST_CAKE, + FRUIT, CREME_CARAMEL; + } + enum Coffee implements Food { + BLACK_COFFEE, DECAF_COFFEE, ESPRESSO, + LATTE, CAPPUCCINO, TEA, HERB_TEA; + } +} ///:~ diff --git a/enums/menu/Meal.java b/enums/menu/Meal.java new file mode 100644 index 00000000..1dee9b81 --- /dev/null +++ b/enums/menu/Meal.java @@ -0,0 +1,41 @@ +//: enums/menu/Meal.java +// ©2015 MindView LLC: see Copyright.txt +package enums.menu; + +public class Meal { + public static void main(String[] args) { + for(int i = 0; i < 5; i++) { + for(Course course : Course.values()) { + Food food = course.randomSelection(); + System.out.println(food); + } + System.out.println("---"); + } + } +} /* Output: +SPRING_ROLLS +VINDALOO +FRUIT +DECAF_COFFEE +--- +SOUP +VINDALOO +FRUIT +TEA +--- +SALAD +BURRITO +FRUIT +TEA +--- +SALAD +BURRITO +CREME_CARAMEL +LATTE +--- +SOUP +BURRITO +TIRAMISU +ESPRESSO +--- +*///:~ diff --git a/enums/menu/Meal2.java b/enums/menu/Meal2.java new file mode 100644 index 00000000..c90db9e7 --- /dev/null +++ b/enums/menu/Meal2.java @@ -0,0 +1,44 @@ +//: enums/menu/Meal2.java +// ©2015 MindView LLC: see Copyright.txt +package enums.menu; +import net.mindview.util.*; + +public enum Meal2 { + APPETIZER(Food.Appetizer.class), + MAINCOURSE(Food.MainCourse.class), + DESSERT(Food.Dessert.class), + COFFEE(Food.Coffee.class); + private Food[] values; + private Meal2(Class kind) { + values = kind.getEnumConstants(); + } + public interface Food { + enum Appetizer implements Food { + SALAD, SOUP, SPRING_ROLLS; + } + enum MainCourse implements Food { + LASAGNE, BURRITO, PAD_THAI, + LENTILS, HUMMOUS, VINDALOO; + } + enum Dessert implements Food { + TIRAMISU, GELATO, BLACK_FOREST_CAKE, + FRUIT, CREME_CARAMEL; + } + enum Coffee implements Food { + BLACK_COFFEE, DECAF_COFFEE, ESPRESSO, + LATTE, CAPPUCCINO, TEA, HERB_TEA; + } + } + public Food randomSelection() { + return Enums.random(values); + } + public static void main(String[] args) { + for(int i = 0; i < 5; i++) { + for(Meal2 meal : Meal2.values()) { + Food food = meal.randomSelection(); + System.out.println(food); + } + System.out.println("---"); + } + } +} /* Same output as Meal.java *///:~ diff --git a/enums/menu/TypeOfFood.java b/enums/menu/TypeOfFood.java new file mode 100644 index 00000000..28be2d69 --- /dev/null +++ b/enums/menu/TypeOfFood.java @@ -0,0 +1,13 @@ +//: enums/menu/TypeOfFood.java +// ©2015 MindView LLC: see Copyright.txt +package enums.menu; +import static enums.menu.Food.*; + +public class TypeOfFood { + public static void main(String[] args) { + Food food = Appetizer.SALAD; + food = MainCourse.LASAGNE; + food = Dessert.GELATO; + food = Coffee.CAPPUCCINO; + } +} ///:~