renames PetriNet to Petrinet and uses the parser as a resource in Main
[petrinet.git] / src / main / java / de / yasc / example / petrinet / Petrinet.java
diff --git a/src/main/java/de/yasc/example/petrinet/Petrinet.java b/src/main/java/de/yasc/example/petrinet/Petrinet.java
new file mode 100644 (file)
index 0000000..f8882f2
--- /dev/null
@@ -0,0 +1,99 @@
+package de.yasc.example.petrinet;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Random;
+import java.util.stream.Collectors;
+
+public final class Petrinet {
+
+    private static final class Place {
+
+        int tokens;
+
+        boolean empty() {
+            return tokens <= 0;
+        }
+
+        void dec() {
+            assert tokens > 0;
+            tokens--;
+        }
+
+        void inc() {
+            tokens++;
+        }
+    }
+
+    private static final class Transition {
+
+        final List<Place> preset;
+        final List<Place> postset;
+
+        public Transition(List<Place> preset, List<Place> postset) {
+            this.preset = preset;
+            this.postset = postset;
+        }
+
+        boolean enabled() {
+            return preset.stream().noneMatch(Place::empty);
+        }
+
+        void fire() {
+            preset.forEach(Place::dec);
+            postset.forEach(Place::inc);
+        }
+    }
+
+    final private Random prng = new Random();
+    final private Place[] places;
+    final private List<Transition> transitions;
+
+    public Petrinet(int places) {
+        this.places = new Place[places];
+        for (int i = 0 ; i < places ; i++)
+            this.places[i] = new Place();
+        transitions = new ArrayList<>();
+    }
+
+    public void addTransistion(Integer[] preset, Integer[] postset) {
+        transitions.add(new Transition(
+                Arrays.stream(preset).map((i) -> places[i]).collect(Collectors.toList()),
+                Arrays.stream(postset).map((i) -> places[i]).collect(Collectors.toList())
+        ));
+    }
+    
+    public void addMarking(Integer ... marking) {
+        Arrays.stream(marking).forEach((i) -> places[i].inc());
+    }
+    
+    public boolean step() {
+        var enabledTransitions = transitions.stream().filter(Transition::enabled).collect(Collectors.toList());
+        if (enabledTransitions.isEmpty()) {
+            return false;
+        } else {
+            transitions.get(prng.nextInt(enabledTransitions.size())).fire();
+            return true;
+        }
+    }
+    
+    public int step(int k) {
+        int i = 0;
+        while (i < k) {
+            if (!step())
+                return i;
+            ++i;
+        }
+        return i;
+    }
+    
+    public Integer[] getMarking() {
+        final var marking = new ArrayList<Integer>();
+        for (int p = 0 ; p < places.length ; p++) {
+            Collections.nCopies(places[p].tokens, p).forEach(marking::add);
+        }
+        return marking.toArray(new Integer[0]);
+    }
+}