--- /dev/null
+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]);
+ }
+}