diff --git a/src/main/java/com/garbagemule/MobArena/things/RandomThingPicker.java b/src/main/java/com/garbagemule/MobArena/things/RandomThingPicker.java new file mode 100644 index 0000000..0b94287 --- /dev/null +++ b/src/main/java/com/garbagemule/MobArena/things/RandomThingPicker.java @@ -0,0 +1,31 @@ +package com.garbagemule.MobArena.things; + +import java.util.List; +import java.util.Random; +import java.util.stream.Collectors; + +public class RandomThingPicker implements ThingPicker { + + private final List pickers; + private final Random random; + + public RandomThingPicker(List pickers, Random random) { + this.pickers = pickers; + this.random = random; + } + + @Override + public Thing pick() { + int index = random.nextInt(pickers.size()); + return pickers.get(index).pick(); + } + + @Override + public String toString() { + String list = pickers.stream() + .map(ThingPicker::toString) + .collect(Collectors.joining(" or ")); + return "(" + list + ")"; + } + +} diff --git a/src/main/java/com/garbagemule/MobArena/things/SingleThingPicker.java b/src/main/java/com/garbagemule/MobArena/things/SingleThingPicker.java new file mode 100644 index 0000000..6534a5b --- /dev/null +++ b/src/main/java/com/garbagemule/MobArena/things/SingleThingPicker.java @@ -0,0 +1,21 @@ +package com.garbagemule.MobArena.things; + +public class SingleThingPicker implements ThingPicker { + + private final Thing thing; + + public SingleThingPicker(Thing thing) { + this.thing = thing; + } + + @Override + public Thing pick() { + return thing; + } + + @Override + public String toString() { + return thing.toString(); + } + +} diff --git a/src/main/java/com/garbagemule/MobArena/things/ThingGroupPicker.java b/src/main/java/com/garbagemule/MobArena/things/ThingGroupPicker.java new file mode 100644 index 0000000..ad548a2 --- /dev/null +++ b/src/main/java/com/garbagemule/MobArena/things/ThingGroupPicker.java @@ -0,0 +1,31 @@ +package com.garbagemule.MobArena.things; + +import java.util.List; +import java.util.stream.Collectors; + +public class ThingGroupPicker implements ThingPicker { + + private final List pickers; + + public ThingGroupPicker(List pickers) { + this.pickers = pickers; + } + + @Override + public Thing pick() { + List things = pickers.stream() + .map(ThingPicker::pick) + .collect(Collectors.toList()); + + return new ThingGroup(things); + } + + @Override + public String toString() { + String list = pickers.stream() + .map(ThingPicker::toString) + .collect(Collectors.joining(" and ")); + return "(" + list + ")"; + } + +} diff --git a/src/main/java/com/garbagemule/MobArena/things/ThingPicker.java b/src/main/java/com/garbagemule/MobArena/things/ThingPicker.java new file mode 100644 index 0000000..a34a40e --- /dev/null +++ b/src/main/java/com/garbagemule/MobArena/things/ThingPicker.java @@ -0,0 +1,22 @@ +package com.garbagemule.MobArena.things; + +/** + * Pickers encapsulate a type of highly specific Factory pattern that revolves + * around choosing from an arbitrary pool of Thing instances without directly + * giving them to or taking them from players. + *

+ * The interface exposes a single method, {@link #pick()}. When invoked, the + * implementation is expected to resolve or create a {@link Thing} instance + * or null. The how and why is entirely up to the implementation, but callers + * must not depend on the return value being stable, even though it may be. + */ +public interface ThingPicker { + + /** + * Pick a thing. + * + * @return a {@link Thing} instance, or null + */ + Thing pick(); + +} diff --git a/src/test/java/com/garbagemule/MobArena/things/RandomThingPickerTest.java b/src/test/java/com/garbagemule/MobArena/things/RandomThingPickerTest.java new file mode 100644 index 0000000..c1fd0b0 --- /dev/null +++ b/src/test/java/com/garbagemule/MobArena/things/RandomThingPickerTest.java @@ -0,0 +1,45 @@ +package com.garbagemule.MobArena.things; + +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class RandomThingPickerTest { + + private RandomThingPicker subject; + private List pickers; + private Random random; + + @Before + public void setup() { + pickers = new ArrayList<>(); + random = mock(Random.class); + subject = new RandomThingPicker(pickers, random); + } + + @Test + public void invokesOnlyChosenPicker() { + ThingPicker decoy = mock(ThingPicker.class); + ThingPicker chosen = mock(ThingPicker.class); + pickers.add(decoy); + pickers.add(decoy); + pickers.add(chosen); + pickers.add(decoy); + when(random.nextInt(pickers.size())).thenReturn(2); + + subject.pick(); + + verify(decoy, never()).pick(); + verify(chosen, times(1)).pick(); + } + +} diff --git a/src/test/java/com/garbagemule/MobArena/things/ThingGroupPickerTest.java b/src/test/java/com/garbagemule/MobArena/things/ThingGroupPickerTest.java new file mode 100644 index 0000000..ae1affb --- /dev/null +++ b/src/test/java/com/garbagemule/MobArena/things/ThingGroupPickerTest.java @@ -0,0 +1,40 @@ +package com.garbagemule.MobArena.things; + +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +public class ThingGroupPickerTest { + + private ThingGroupPicker subject; + private List pickers; + + @Before + public void setup() { + pickers = new ArrayList<>(); + subject = new ThingGroupPicker(pickers); + } + + @Test + public void invokesAllPickers() { + ThingPicker first = mock(ThingPicker.class); + ThingPicker second = mock(ThingPicker.class); + ThingPicker third = mock(ThingPicker.class); + pickers.add(first); + pickers.add(second); + pickers.add(third); + + subject.pick(); + + verify(first, times(1)).pick(); + verify(second, times(1)).pick(); + verify(third, times(1)).pick(); + } + +}