소스 검색

аспекты работают, бот движется и жрёт, даже без наличия ума

kpmy 7 년 전
부모
커밋
58c3815973
41개의 변경된 파일981개의 추가작업 그리고 164개의 파일을 삭제
  1. 1 0
      .gitignore
  2. 7 0
      pom.xml
  3. 21 0
      src/main/java/in/ocsf/frei/geld/core/Ctx.java
  4. 22 0
      src/main/java/in/ocsf/frei/geld/core/REST.java
  5. 4 0
      src/main/java/in/ocsf/frei/geld/core/model/ContextEvent.java
  6. 49 139
      src/main/java/in/ocsf/frei/geld/core/model/Dwarf.java
  7. 49 9
      src/main/java/in/ocsf/frei/geld/core/model/DwarfContext.java
  8. 1 0
      src/main/java/in/ocsf/frei/geld/core/model/LiveCycle.java
  9. 1 1
      src/main/java/in/ocsf/frei/geld/core/model/SimpleEvent.java
  10. 2 2
      src/main/java/in/ocsf/frei/geld/core/model/World.java
  11. 42 0
      src/main/java/in/ocsf/frei/geld/core/model/aspects/ActivityAspect.java
  12. 29 0
      src/main/java/in/ocsf/frei/geld/core/model/aspects/ChangeExecutorEvent.java
  13. 72 0
      src/main/java/in/ocsf/frei/geld/core/model/aspects/DecisionAspect.java
  14. 36 0
      src/main/java/in/ocsf/frei/geld/core/model/aspects/DecisionDescriptor.java
  15. 6 0
      src/main/java/in/ocsf/frei/geld/core/model/aspects/DecisionEvent.java
  16. 4 1
      src/main/java/in/ocsf/frei/geld/core/model/aspects/DwarfAspect.java
  17. 4 1
      src/main/java/in/ocsf/frei/geld/core/model/aspects/DwarfDefaultAspect.java
  18. 5 0
      src/main/java/in/ocsf/frei/geld/core/model/aspects/DwarfTask.java
  19. 59 0
      src/main/java/in/ocsf/frei/geld/core/model/aspects/DwarfTaskDescriptor.java
  20. 16 0
      src/main/java/in/ocsf/frei/geld/core/model/aspects/DwarfTaskExecutor.java
  21. 56 0
      src/main/java/in/ocsf/frei/geld/core/model/aspects/EnergyAspect.java
  22. 5 0
      src/main/java/in/ocsf/frei/geld/core/model/aspects/ExecutorStatus.java
  23. 39 0
      src/main/java/in/ocsf/frei/geld/core/model/aspects/FeelingsAspect.java
  24. 62 0
      src/main/java/in/ocsf/frei/geld/core/model/aspects/ManagerAspect.java
  25. 136 0
      src/main/java/in/ocsf/frei/geld/core/model/aspects/RunnerAspect.java
  26. 32 0
      src/main/java/in/ocsf/frei/geld/core/model/aspects/RunnerCode.java
  27. 6 0
      src/main/java/in/ocsf/frei/geld/core/model/aspects/RunnerEvent.java
  28. 18 0
      src/main/java/in/ocsf/frei/geld/core/model/aspects/StartRunnerEvent.java
  29. 10 0
      src/main/java/in/ocsf/frei/geld/core/model/aspects/StopRunnerEvent.java
  30. 47 0
      src/main/java/in/ocsf/frei/geld/core/model/aspects/TaskAspect.java
  31. 60 0
      src/main/java/in/ocsf/frei/geld/core/model/aspects/VisionAspect.java
  32. 2 0
      src/main/java/in/ocsf/frei/geld/core/repo/DwarfRepository.java
  33. 4 4
      src/main/java/in/ocsf/frei/geld/core/rest/DevController.java
  34. 10 2
      src/main/java/in/ocsf/frei/geld/core/service/DwarfService.java
  35. 5 1
      src/main/java/in/ocsf/frei/geld/core/service/LiveCycleService.java
  36. BIN
      src/main/resources/static/2fcrYFNaTjcS6g4U3t-Y5ZjZjT5FdEJ140U2DJYC3mY.woff2
  37. 16 1
      src/main/resources/static/components/root.html
  38. 17 2
      src/main/resources/static/components/root.js
  39. BIN
      src/main/resources/static/favicon.ico
  40. 23 0
      src/main/resources/static/fonts.css
  41. 3 1
      src/main/resources/static/index.html

+ 1 - 0
.gitignore

@@ -16,3 +16,4 @@ hs_err_pid*
 /*.iml
 /*.ipr
 /*.iws
+/src/main/resources/static/bower_components

+ 7 - 0
pom.xml

@@ -71,6 +71,13 @@
             <version>3.7</version>
         </dependency>
 
+        <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-math3 -->
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-math3</artifactId>
+            <version>3.6.1</version>
+        </dependency>
+
     </dependencies>
 
     <build>

+ 21 - 0
src/main/java/in/ocsf/frei/geld/core/Ctx.java

@@ -0,0 +1,21 @@
+package in.ocsf.frei.geld.core;/* kpmy 25.02.2017 */
+
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.stereotype.Service;
+
+@Service
+public class Ctx implements ApplicationContextAware {
+
+    private static ApplicationContext context;
+
+    public static ApplicationContext getContext() {
+        return context;
+    }
+
+    @Override
+    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+        context = applicationContext;
+    }
+}

+ 22 - 0
src/main/java/in/ocsf/frei/geld/core/REST.java

@@ -0,0 +1,22 @@
+package in.ocsf.frei.geld.core;/* kpmy 26.11.2017 */
+
+import in.ocsf.frei.geld.core.model.Dwarf;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
+import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurer;
+import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurerAdapter;
+
+@Configuration
+public class REST {
+    @Bean
+    public RepositoryRestConfigurer repositoryRestConfigurer() {
+
+        return new RepositoryRestConfigurerAdapter() {
+            @Override
+            public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
+                config.exposeIdsFor(Dwarf.class);
+            }
+        };
+    }
+}

+ 4 - 0
src/main/java/in/ocsf/frei/geld/core/model/ContextEvent.java

@@ -0,0 +1,4 @@
+package in.ocsf.frei.geld.core.model;/* kpmy 25.11.2017 */
+
+public interface ContextEvent {
+}

+ 49 - 139
src/main/java/in/ocsf/frei/geld/core/model/Dwarf.java

@@ -1,19 +1,12 @@
 package in.ocsf.frei.geld.core.model;/* kpmy 15.11.2017 */
 
-import org.apache.commons.lang3.Range;
-import org.apache.commons.lang3.tuple.MutablePair;
+import in.ocsf.frei.geld.core.model.aspects.*;
 import org.bson.types.ObjectId;
 import org.springframework.data.annotation.Id;
 import org.springframework.data.annotation.Version;
 import org.springframework.data.mongodb.core.mapping.DBRef;
 import org.springframework.data.mongodb.core.mapping.Document;
 
-import java.util.HashMap;
-import java.util.Map;
-import java.util.function.BiConsumer;
-import java.util.function.Consumer;
-import java.util.stream.Collectors;
-
 @Document(collection = "dwarf")
 public class Dwarf {
 
@@ -43,14 +36,48 @@ public class Dwarf {
 
     private VisionAspect vision;
 
+    private TaskAspect tasks;
+
+    private ManagerAspect manager;
+
+    private DecisionAspect decision;
+
+    private RunnerAspect runner;
+
     @DBRef
     private World world;
 
     public Dwarf() {
-        energy = new EnergyAspect();
-        activity = new ActivityAspect();
-        feelings = new FeelingsAspect();
-        vision = new VisionAspect();
+    }
+
+    public static Dwarf getInstance(World world) {
+        Dwarf ret = new Dwarf();
+        ret.world = world;
+        ret.energy = EnergyAspect.getInstance();
+        ret.activity = ActivityAspect.getInstance();
+        ret.feelings = FeelingsAspect.getInstance();
+        ret.vision = VisionAspect.getInstance();
+        ret.tasks = TaskAspect.getInstance();
+        ret.manager = ManagerAspect.getInstance();
+        ret.decision = DecisionAspect.getInstance();
+        ret.runner = RunnerAspect.getInstance();
+        return ret;
+    }
+
+    public ManagerAspect getManager() {
+        return manager;
+    }
+
+    public void setManager(ManagerAspect manager) {
+        this.manager = manager;
+    }
+
+    public TaskAspect getTasks() {
+        return tasks;
+    }
+
+    public void setTasks(TaskAspect tasks) {
+        this.tasks = tasks;
     }
 
     public VisionAspect getVision() {
@@ -101,8 +128,8 @@ public class Dwarf {
         this.death = death;
     }
 
-    public ObjectId getId() {
-        return id;
+    public String getId() {
+        return id.toHexString();
     }
 
     public void setId(ObjectId id) {
@@ -149,136 +176,19 @@ public class Dwarf {
         this.hour = hour;
     }
 
-    public static class ActivityAspect implements DwarfAspect {
-
-        private boolean active;
-
-        public ActivityAspect() {
-            this.active = true;
-        }
-
-        @Override
-        public BiConsumer<DwarfContext, Dwarf> perform() {
-            return (ctx, dwarf) -> {
-                if (ctx.getConsequences().contains(SimpleConsequence.SLEEP)) {
-                    active = false;
-                    ctx.getConsequences().remove(SimpleConsequence.SLEEP);
-                } else if (ctx.getConsequences().contains(SimpleConsequence.AWAKE)) {
-                    active = true;
-                    ctx.getConsequences().remove(SimpleConsequence.AWAKE);
-                }
-            };
-        }
-
-        public boolean isActive() {
-            return active;
-        }
-
-        public void setActive(boolean active) {
-            this.active = active;
-        }
+    public DecisionAspect getDecision() {
+        return decision;
     }
 
-    public static class EnergyAspect implements DwarfAspect {
-
-        private static final Range<Double> sleepRange = Range.between(LiveCycle.DAYLY_ENERGY * 2 / 3, LiveCycle.DAYLY_ENERGY);
-
-        private Double energy;
-        private Double loss;
-
-        public EnergyAspect() {
-            this.energy = LiveCycle.TOTAL_ENERGY;
-            this.loss = 0.0;
-        }
-
-        public Double getEnergy() {
-            return energy;
-        }
-
-        public void setEnergy(Double energy) {
-            this.energy = energy;
-        }
-
-        @Override
-        public BiConsumer<DwarfContext, Dwarf> perform() {
-            return (context, dwarf) -> {
-                double deltaLoss = (LiveCycle.DAYLY_ENERGY / LiveCycle.HOURS);
-                this.energy = this.energy - deltaLoss;
-                this.loss = this.loss + deltaLoss;
-                if (this.energy <= 0) {
-                    context.addSimpleConsequence(this, SimpleConsequence.DEATH);
-                } else if (sleepRange.contains(this.loss)) {
-                    context.addSimpleConsequence(this, SimpleConsequence.SLEEP);
-                } else if (sleepRange.isBefore(this.loss)) {
-                    this.loss = deltaLoss;
-                    context.addSimpleConsequence(this, SimpleConsequence.AWAKE);
-                }
-            };
-        }
+    public void setDecision(DecisionAspect decision) {
+        this.decision = decision;
     }
 
-    public static class FeelingsAspect implements DwarfAspect {
-
-        private double hunger;
-
-        public FeelingsAspect() {
-            this.hunger = 0.0;
-        }
-
-        public double getHunger() {
-            return hunger;
-        }
-
-        public void setHunger(double hunger) {
-            this.hunger = hunger;
-        }
-
-        @Override
-        public BiConsumer<DwarfContext, Dwarf> perform() {
-            return (ctx, d) -> {
-                this.hunger = (Math.min(LiveCycle.DAYLY_ENERGY, LiveCycle.TOTAL_ENERGY - d.getEnergy().getEnergy()) / LiveCycle.DAYLY_ENERGY) * 100;
-            };
-        }
+    public RunnerAspect getRunner() {
+        return runner;
     }
 
-    public static class VisionAspect implements DwarfDefaultAspect {
-
-        private Map<String, MutablePair<WorldObjectType, Object>> frame;
-
-        @DBRef
-        private World.DwarfPoint self;
-
-        public VisionAspect() {
-            frame = new HashMap<>();
-        }
-
-        public Map<String, MutablePair<WorldObjectType, Object>> getFrame() {
-            return frame;
-        }
-
-        public void setFrame(Map<String, MutablePair<WorldObjectType, Object>> frame) {
-            this.frame = frame;
-        }
-
-        @Override
-        public Consumer<Dwarf> skip() {
-            return (d) -> frame = new HashMap<>();
-        }
-
-        public World.DwarfPoint getSelf() {
-            return self;
-        }
-
-        public void setSelf(World.DwarfPoint self) {
-            this.self = self;
-        }
-
-        @Override
-        public BiConsumer<DwarfContext, Dwarf> perform() {
-            return (ctx, dwarf) -> {
-                self = ctx.getDwarfPosition(dwarf);
-                frame = ctx.getAllAround(self).stream().filter(s -> !s.getPoint().equals(self.getPoint())).collect(Collectors.toMap(s -> s.getPoint().toString(), World.Something::getRef, (same, key) -> same));
-            };
-        }
+    public void setRunner(RunnerAspect runner) {
+        this.runner = runner;
     }
 }

+ 49 - 9
src/main/java/in/ocsf/frei/geld/core/model/DwarfContext.java

@@ -1,13 +1,18 @@
 package in.ocsf.frei.geld.core.model;/* kpmy 24.11.2017 */
 
+import in.ocsf.frei.geld.core.model.aspects.DwarfAspect;
 import in.ocsf.frei.geld.core.repo.WorldDwarfObjectRepository;
 import in.ocsf.frei.geld.core.repo.WorldObjectRepository;
+import org.apache.commons.lang3.tuple.Pair;
 import org.springframework.context.ApplicationContext;
+import org.springframework.dao.OptimisticLockingFailureException;
 
 import java.util.ArrayList;
-import java.util.HashSet;
+import java.util.Arrays;
 import java.util.List;
-import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
 
 import static in.ocsf.frei.geld.core.model.QWorld_Something.something;
 
@@ -15,7 +20,7 @@ public class DwarfContext {
 
     private ApplicationContext context;
 
-    private Set<SimpleConsequence> consequences = new HashSet<>();
+    private List<Pair<DwarfAspect, ContextEvent>> events = new ArrayList<>();
 
     private Long hour;
 
@@ -23,16 +28,20 @@ public class DwarfContext {
         this.context = context;
     }
 
-    public void addSimpleConsequence(Dwarf.EnergyAspect aspect, SimpleConsequence consequence) {
-        consequences.add(consequence);
+    public void addEvent(DwarfAspect aspect, ContextEvent event) {
+        events.add(Pair.of(aspect, event));
     }
 
-    public Set<SimpleConsequence> getConsequences() {
-        return consequences;
+    public boolean hasSimpleEvent(SimpleEvent event) {
+        return events.stream().filter(p -> event.equals(p.getValue())).count() > 0;
     }
 
-    public void setConsequences(Set<SimpleConsequence> consequences) {
-        this.consequences = consequences;
+    public List<Object> getEvents(Class<? extends ContextEvent> cls) {
+        return events.stream().filter(p -> cls.isInstance(p.getValue())).map(Pair::getValue).collect(Collectors.toList());
+    }
+
+    public void doneWith(ContextEvent event) {
+        events = events.stream().filter(p -> !event.equals(p.getValue())).collect(Collectors.toList());
     }
 
     public Long getHour() {
@@ -54,4 +63,35 @@ public class DwarfContext {
         pointRepo.findAll(something.point.x.between(self.getPoint().getX() - LiveCycle.VISION_LENGTH, self.getPoint().getX() + LiveCycle.VISION_LENGTH).and(something.point.y.between(self.getPoint().getY() - LiveCycle.VISION_LENGTH, self.getPoint().getY() + LiveCycle.VISION_LENGTH)).and(something.world.id.eq(self.getWorld().getId()))).forEach(ret::add);
         return ret;
     }
+
+    public boolean move(Dwarf dwarf, int x, int y) {
+        WorldObjectRepository pointRepo = context.getBean(WorldObjectRepository.class);
+        World.DwarfPoint old = getDwarfPosition(dwarf);
+        try {
+            World.DwarfPoint neo = new World.DwarfPoint(old.getWorld(), old.getDwarf(), old.getPoint().getX() + x, old.getPoint().getY() + y);
+            Stream<World.Something> inPlace = StreamSupport.stream(pointRepo.findAll(something.point.x.eq(neo.getPoint().getX()).and(something.point.y.eq(neo.getPoint().getY()))).spliterator(), false);
+            if (inPlace.filter(s -> Arrays.asList(WorldObjectType.DWARF).contains(s.getRef().getKey())).count() > 0)
+                return false;
+            pointRepo.save(neo);
+            pointRepo.delete(old);
+        } catch (OptimisticLockingFailureException e) {
+            return false;
+        }
+        return true;
+    }
+
+    public boolean eat(Dwarf dwarf) {
+        WorldObjectRepository pointRepo = context.getBean(WorldObjectRepository.class);
+        World.DwarfPoint old = getDwarfPosition(dwarf);
+        try {
+            Iterable<World.Something> foodInPlace = pointRepo.findAll(something.point.x.eq(old.getPoint().getX()).and(something.point.y.eq(old.getPoint().getY())).and(something.point.type.eq(WorldObjectType.FOOD)));
+            if (StreamSupport.stream(foodInPlace.spliterator(), false).count() == 0)
+                return false;
+            World.FoodPoint food = StreamSupport.stream(foodInPlace.spliterator(), false).findFirst().map(o -> (World.FoodPoint) o).orElseThrow(RuntimeException::new);
+            pointRepo.delete(food);
+        } catch (OptimisticLockingFailureException e) {
+            return false;
+        }
+        return true;
+    }
 }

+ 1 - 0
src/main/java/in/ocsf/frei/geld/core/model/LiveCycle.java

@@ -6,4 +6,5 @@ public class LiveCycle {
     public static final double TOTAL_ENERGY = 300_000.0;
     public static final double DAYLY_ENERGY = 2_500.0;
     public static final int VISION_LENGTH = 10;
+    public static final int MAX_STEPS = 8;
 }

+ 1 - 1
src/main/java/in/ocsf/frei/geld/core/model/SimpleConsequence.java → src/main/java/in/ocsf/frei/geld/core/model/SimpleEvent.java

@@ -1,5 +1,5 @@
 package in.ocsf.frei.geld.core.model;/* kpmy 24.11.2017 */
 
-public enum SimpleConsequence {
+public enum SimpleEvent implements ContextEvent {
     DEATH, SLEEP, AWAKE
 }

+ 2 - 2
src/main/java/in/ocsf/frei/geld/core/model/World.java

@@ -73,7 +73,7 @@ public class World {
         }
 
         public static WorldPoint2D fromString(String value) {
-            String[] p = value.split("-", -1);
+            String[] p = value.split("_", -1);
             return new WorldPoint2D(Integer.parseInt(p[1]), Integer.parseInt(p[2]), WorldObjectType.valueOf(p[0]));
         }
 
@@ -103,7 +103,7 @@ public class World {
 
         @Override
         public String toString() {
-            return type.name() + "-" + x + "-" + y;
+            return type.name() + "_" + x + "_" + y;
         }
 
         @Override

+ 42 - 0
src/main/java/in/ocsf/frei/geld/core/model/aspects/ActivityAspect.java

@@ -0,0 +1,42 @@
+package in.ocsf.frei.geld.core.model.aspects;/* kpmy 25.11.2017 */
+
+import in.ocsf.frei.geld.core.model.Dwarf;
+import in.ocsf.frei.geld.core.model.DwarfContext;
+import in.ocsf.frei.geld.core.model.SimpleEvent;
+
+import java.util.function.BiConsumer;
+
+public class ActivityAspect implements DwarfAspect {
+
+    private boolean active;
+
+    public ActivityAspect() {
+    }
+
+    public static ActivityAspect getInstance() {
+        ActivityAspect ret = new ActivityAspect();
+        ret.active = true;
+        return ret;
+    }
+
+    @Override
+    public BiConsumer<DwarfContext, Dwarf> perform() {
+        return (ctx, dwarf) -> {
+            if (ctx.hasSimpleEvent(SimpleEvent.SLEEP)) {
+                active = false;
+                ctx.doneWith(SimpleEvent.SLEEP);
+            } else if (ctx.hasSimpleEvent(SimpleEvent.AWAKE)) {
+                active = true;
+                ctx.doneWith(SimpleEvent.AWAKE);
+            }
+        };
+    }
+
+    public boolean isActive() {
+        return active;
+    }
+
+    public void setActive(boolean active) {
+        this.active = active;
+    }
+}

+ 29 - 0
src/main/java/in/ocsf/frei/geld/core/model/aspects/ChangeExecutorEvent.java

@@ -0,0 +1,29 @@
+package in.ocsf.frei.geld.core.model.aspects;/* kpmy 25.11.2017 */
+
+
+public class ChangeExecutorEvent implements DecisionEvent {
+
+    DwarfTaskDescriptor prev;
+    DwarfTaskDescriptor curr;
+
+    public ChangeExecutorEvent(DwarfTaskDescriptor prev, DwarfTaskDescriptor curr) {
+        this.prev = prev;
+        this.curr = curr;
+    }
+
+    public DwarfTaskDescriptor getPrev() {
+        return prev;
+    }
+
+    public void setPrev(DwarfTaskDescriptor prev) {
+        this.prev = prev;
+    }
+
+    public DwarfTaskDescriptor getCurr() {
+        return curr;
+    }
+
+    public void setCurr(DwarfTaskDescriptor curr) {
+        this.curr = curr;
+    }
+}

+ 72 - 0
src/main/java/in/ocsf/frei/geld/core/model/aspects/DecisionAspect.java

@@ -0,0 +1,72 @@
+package in.ocsf.frei.geld.core.model.aspects;/* kpmy 25.11.2017 */
+
+import in.ocsf.frei.geld.core.model.Dwarf;
+import in.ocsf.frei.geld.core.model.DwarfContext;
+import org.apache.commons.lang3.RandomUtils;
+
+import java.util.*;
+import java.util.function.BiConsumer;
+import java.util.stream.Collectors;
+
+public class DecisionAspect implements DwarfDefaultAspect {
+
+    private Map<String, DecisionDescriptor> decisions;
+
+    public DecisionAspect() {
+    }
+
+    public static DecisionAspect getInstance() {
+        DecisionAspect ret = new DecisionAspect();
+        ret.decisions = new HashMap<>();
+        return ret;
+    }
+
+    public Map<String, DecisionDescriptor> getDecisions() {
+        return decisions;
+    }
+
+    public void setDecisions(Map<String, DecisionDescriptor> decisions) {
+        this.decisions = decisions;
+    }
+
+    private List<String> getDecision(DwarfTaskDescriptor task) {
+        List<RunnerCode> ret = new ArrayList<>();
+        int len = RandomUtils.nextInt(1, 20);
+        while (len > 0) {
+            ret.add(RunnerCode.values()[RandomUtils.nextInt(0, RunnerCode.values().length)]);
+            len--;
+        }
+        return ret.stream().map(c -> c.getCode()).collect(Collectors.toList());
+    }
+
+    @Override
+    public BiConsumer<DwarfContext, Dwarf> perform() {
+        return (ctx, dwarf) -> {
+            List<DecisionEvent> dl = (List) ctx.getEvents(DecisionEvent.class);
+            dl.forEach(e -> {
+                if (e instanceof ChangeExecutorEvent) {
+                    ctx.doneWith(e);
+                    Optional.ofNullable(decisions.get(((ChangeExecutorEvent) e).prev.getId())).filter(d -> Arrays.asList(ExecutorStatus.PENDING, ExecutorStatus.NONE).contains(d.getStatus())).ifPresent(d -> {
+                        ctx.addEvent(this, new StopRunnerEvent(d));
+                        d.setStatus(ExecutorStatus.BREAK);
+                    });
+                    List<String> code = getDecision(((ChangeExecutorEvent) e).curr);
+                    DecisionDescriptor decision = new DecisionDescriptor();
+                    decision.setCode(code);
+                    decision.setStatus(ExecutorStatus.NONE);
+                    decision.setId(((ChangeExecutorEvent) e).curr.getId());
+                    ctx.addEvent(this, new StartRunnerEvent(decision));
+                    decisions.put(decision.getId(), decision);
+                }
+            });
+        };
+    }
+
+    public ExecutorStatus getStatus(String id) {
+        return Optional.ofNullable(decisions.get(id)).map(DecisionDescriptor::getStatus).orElse(ExecutorStatus.NONE);
+    }
+
+    public void setStatus(String id, ExecutorStatus status) {
+        Optional.ofNullable(decisions.get(id)).ifPresent(d -> d.setStatus(status));
+    }
+}

+ 36 - 0
src/main/java/in/ocsf/frei/geld/core/model/aspects/DecisionDescriptor.java

@@ -0,0 +1,36 @@
+package in.ocsf.frei.geld.core.model.aspects;/* kpmy 26.11.2017 */
+
+import java.util.List;
+
+public class DecisionDescriptor {
+
+    private List<String> code;
+
+    private String id;
+
+    private ExecutorStatus status;
+
+    public List<String> getCode() {
+        return code;
+    }
+
+    public void setCode(List<String> code) {
+        this.code = code;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public ExecutorStatus getStatus() {
+        return status;
+    }
+
+    public void setStatus(ExecutorStatus status) {
+        this.status = status;
+    }
+}

+ 6 - 0
src/main/java/in/ocsf/frei/geld/core/model/aspects/DecisionEvent.java

@@ -0,0 +1,6 @@
+package in.ocsf.frei.geld.core.model.aspects;/* kpmy 25.11.2017 */
+
+import in.ocsf.frei.geld.core.model.ContextEvent;
+
+public interface DecisionEvent extends ContextEvent {
+}

+ 4 - 1
src/main/java/in/ocsf/frei/geld/core/model/DwarfAspect.java → src/main/java/in/ocsf/frei/geld/core/model/aspects/DwarfAspect.java

@@ -1,4 +1,7 @@
-package in.ocsf.frei.geld.core.model;/* kpmy 24.11.2017 */
+package in.ocsf.frei.geld.core.model.aspects;/* kpmy 24.11.2017 */
+
+import in.ocsf.frei.geld.core.model.Dwarf;
+import in.ocsf.frei.geld.core.model.DwarfContext;
 
 import java.util.function.BiConsumer;
 import java.util.function.BiFunction;

+ 4 - 1
src/main/java/in/ocsf/frei/geld/core/model/DwarfDefaultAspect.java → src/main/java/in/ocsf/frei/geld/core/model/aspects/DwarfDefaultAspect.java

@@ -1,4 +1,7 @@
-package in.ocsf.frei.geld.core.model;/* kpmy 25.11.2017 */
+package in.ocsf.frei.geld.core.model.aspects;/* kpmy 25.11.2017 */
+
+import in.ocsf.frei.geld.core.model.Dwarf;
+import in.ocsf.frei.geld.core.model.DwarfContext;
 
 import java.util.function.BiFunction;
 

+ 5 - 0
src/main/java/in/ocsf/frei/geld/core/model/aspects/DwarfTask.java

@@ -0,0 +1,5 @@
+package in.ocsf.frei.geld.core.model.aspects;/* kpmy 25.11.2017 */
+
+public enum DwarfTask {
+    EAT, REST
+}

+ 59 - 0
src/main/java/in/ocsf/frei/geld/core/model/aspects/DwarfTaskDescriptor.java

@@ -0,0 +1,59 @@
+package in.ocsf.frei.geld.core.model.aspects;/* kpmy 25.11.2017 */
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.commons.math3.complex.Complex;
+import org.apache.commons.math3.complex.ComplexFormat;
+
+public class DwarfTaskDescriptor {
+
+    private String id;
+
+    private DwarfTask task;
+
+    private String value;
+
+    public DwarfTaskDescriptor() {
+    }
+
+    public static DwarfTaskDescriptor getInstance(DwarfTask task, Complex value) {
+        DwarfTaskDescriptor ret = new DwarfTaskDescriptor();
+        ret.id = RandomStringUtils.randomAlphanumeric(10);
+        ret.setComplexValue(value);
+        ret.task = task;
+        return ret;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public DwarfTask getTask() {
+        return task;
+    }
+
+    public void setTask(DwarfTask task) {
+        this.task = task;
+    }
+
+    @JsonIgnore
+    public Complex getComplexValue() {
+        return ComplexFormat.getInstance().parse(value);
+    }
+
+    public void setComplexValue(Complex value) {
+        this.value = ComplexFormat.getInstance().format(value);
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    public void setValue(String value) {
+        this.value = value;
+    }
+}

+ 16 - 0
src/main/java/in/ocsf/frei/geld/core/model/aspects/DwarfTaskExecutor.java

@@ -0,0 +1,16 @@
+package in.ocsf.frei.geld.core.model.aspects;/* kpmy 25.11.2017 */
+
+public class DwarfTaskExecutor {
+
+    private DwarfTaskDescriptor descriptor;
+
+    public DwarfTaskDescriptor getDescriptor() {
+        return descriptor;
+    }
+
+    public void setDescriptor(DwarfTaskDescriptor descriptor) {
+        this.descriptor = descriptor;
+    }
+
+
+}

+ 56 - 0
src/main/java/in/ocsf/frei/geld/core/model/aspects/EnergyAspect.java

@@ -0,0 +1,56 @@
+package in.ocsf.frei.geld.core.model.aspects;/* kpmy 25.11.2017 */
+
+import in.ocsf.frei.geld.core.model.Dwarf;
+import in.ocsf.frei.geld.core.model.DwarfContext;
+import in.ocsf.frei.geld.core.model.LiveCycle;
+import in.ocsf.frei.geld.core.model.SimpleEvent;
+import org.apache.commons.lang3.Range;
+
+import java.util.function.BiConsumer;
+
+public class EnergyAspect implements DwarfAspect {
+
+    private static final Range<Double> sleepRange = Range.between(LiveCycle.DAYLY_ENERGY * 2 / 3, LiveCycle.DAYLY_ENERGY);
+
+    private Double energy;
+    private Double loss;
+
+    public EnergyAspect() {
+    }
+
+    public static EnergyAspect getInstance() {
+        EnergyAspect ret = new EnergyAspect();
+        ret.energy = LiveCycle.TOTAL_ENERGY;
+        ret.loss = 0.0;
+        return ret;
+    }
+
+    public Double getEnergy() {
+        return energy;
+    }
+
+    public void setEnergy(Double energy) {
+        this.energy = energy;
+    }
+
+    @Override
+    public BiConsumer<DwarfContext, Dwarf> perform() {
+        return (context, dwarf) -> {
+            double deltaLoss = (LiveCycle.DAYLY_ENERGY / LiveCycle.HOURS);
+            this.energy = this.energy - deltaLoss;
+            this.loss = this.loss + deltaLoss;
+            if (this.energy <= 0) {
+                context.addEvent(this, SimpleEvent.DEATH);
+            } else if (sleepRange.contains(this.loss)) {
+                context.addEvent(this, SimpleEvent.SLEEP);
+            } else if (sleepRange.isBefore(this.loss)) {
+                this.loss = deltaLoss;
+                context.addEvent(this, SimpleEvent.AWAKE);
+            }
+        };
+    }
+
+    public void addFood() {
+        this.energy += 2500;
+    }
+}

+ 5 - 0
src/main/java/in/ocsf/frei/geld/core/model/aspects/ExecutorStatus.java

@@ -0,0 +1,5 @@
+package in.ocsf.frei.geld.core.model.aspects;/* kpmy 26.11.2017 */
+
+public enum ExecutorStatus {
+    NONE, BREAK, PENDING, OK, ERROR
+}

+ 39 - 0
src/main/java/in/ocsf/frei/geld/core/model/aspects/FeelingsAspect.java

@@ -0,0 +1,39 @@
+package in.ocsf.frei.geld.core.model.aspects;/* kpmy 25.11.2017 */
+
+import in.ocsf.frei.geld.core.model.Dwarf;
+import in.ocsf.frei.geld.core.model.DwarfContext;
+import in.ocsf.frei.geld.core.model.LiveCycle;
+
+import java.util.function.BiConsumer;
+
+public class FeelingsAspect implements DwarfAspect {
+
+    private static final int HUNGER_DAYS = 3;
+
+    private double hunger;
+
+    public FeelingsAspect() {
+
+    }
+
+    public static FeelingsAspect getInstance() {
+        FeelingsAspect ret = new FeelingsAspect();
+        ret.hunger = 0.0;
+        return ret;
+    }
+
+    public double getHunger() {
+        return hunger;
+    }
+
+    public void setHunger(double hunger) {
+        this.hunger = hunger;
+    }
+
+    @Override
+    public BiConsumer<DwarfContext, Dwarf> perform() {
+        return (ctx, d) -> {
+            this.hunger = (Math.min(HUNGER_DAYS * LiveCycle.DAYLY_ENERGY, LiveCycle.TOTAL_ENERGY - d.getEnergy().getEnergy()) / (HUNGER_DAYS * LiveCycle.DAYLY_ENERGY)) * 100;
+        };
+    }
+}

+ 62 - 0
src/main/java/in/ocsf/frei/geld/core/model/aspects/ManagerAspect.java

@@ -0,0 +1,62 @@
+package in.ocsf.frei.geld.core.model.aspects;/* kpmy 25.11.2017 */
+
+import in.ocsf.frei.geld.core.model.Dwarf;
+import in.ocsf.frei.geld.core.model.DwarfContext;
+import org.apache.commons.math3.complex.Complex;
+
+import java.util.Arrays;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+
+import static in.ocsf.frei.geld.core.model.aspects.ExecutorStatus.*;
+
+public class ManagerAspect implements DwarfDefaultAspect {
+
+    private static BiFunction<Complex, Complex, Boolean> deltaF = (r, l) -> Math.abs(r.abs() - l.abs()) > 0.2;
+    private DwarfTaskExecutor executor;
+
+    public static ManagerAspect getInstance() {
+        ManagerAspect ret = new ManagerAspect();
+        return ret;
+    }
+
+    public DwarfTaskExecutor getExecutor() {
+        return executor;
+    }
+
+    public void setExecutor(DwarfTaskExecutor executor) {
+        this.executor = executor;
+    }
+
+    @Override
+    public BiConsumer<DwarfContext, Dwarf> perform() {
+        return (ctx, dwarf) -> {
+            if (executor == null) {
+                executor = new DwarfTaskExecutor();
+                executor.setDescriptor(TaskAspect.REST);
+            }
+
+            DwarfTaskDescriptor top = dwarf.getTasks().getQueue().values().stream().sorted((l, r) -> {
+                Complex lc = l.getComplexValue();
+                Complex rc = r.getComplexValue();
+                return -Double.valueOf(lc.abs()).compareTo(Double.valueOf(rc.abs()));
+            }).findFirst().orElse(TaskAspect.REST);
+
+            if (top.getTask() != executor.getDescriptor().getTask()) {
+                if (deltaF.apply(top.getComplexValue(), executor.getDescriptor().getComplexValue())) {
+                    ctx.addEvent(this, new ChangeExecutorEvent(executor.getDescriptor(), top));
+                    executor.setDescriptor(top);
+                }
+            } else if (!top.getComplexValue().equals(executor.getDescriptor().getComplexValue())) {
+                top.setId(executor.getDescriptor().getId());
+                executor.setDescriptor(top);
+            }
+
+            if (executor.getDescriptor().getTask() != DwarfTask.REST) {
+                ExecutorStatus status = dwarf.getDecision().getStatus(executor.getDescriptor().getId());
+                if (Arrays.asList(OK, ERROR, BREAK).contains(status))
+                    executor = null;
+            }
+        };
+    }
+}

+ 136 - 0
src/main/java/in/ocsf/frei/geld/core/model/aspects/RunnerAspect.java

@@ -0,0 +1,136 @@
+package in.ocsf.frei.geld.core.model.aspects;/* kpmy 25.11.2017 */
+
+import in.ocsf.frei.geld.core.model.Dwarf;
+import in.ocsf.frei.geld.core.model.DwarfContext;
+import in.ocsf.frei.geld.core.model.LiveCycle;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.BiConsumer;
+
+import static in.ocsf.frei.geld.core.model.aspects.ExecutorStatus.*;
+
+public class RunnerAspect implements DwarfDefaultAspect {
+
+    private String id;
+
+    private List<String> code;
+
+    private int pos;
+
+    private int left;
+
+    private boolean error;
+
+    public RunnerAspect() {
+
+    }
+
+    public static RunnerAspect getInstance() {
+        RunnerAspect ret = new RunnerAspect();
+        ret.left = LiveCycle.MAX_STEPS;
+        ret.pos = -1;
+        ret.code = new ArrayList<>();
+        ret.error = false;
+        return ret;
+    }
+
+    public List<String> getCode() {
+        return code;
+    }
+
+    public void setCode(List<String> code) {
+        this.code = code;
+    }
+
+    public int getPos() {
+        return pos;
+    }
+
+    public void setPos(int pos) {
+        this.pos = pos;
+    }
+
+    public int getLeft() {
+        return left;
+    }
+
+    public void setLeft(int left) {
+        this.left = left;
+    }
+
+    public boolean isError() {
+        return error;
+    }
+
+    public void setError(boolean error) {
+        this.error = error;
+    }
+
+    @Override
+    public BiConsumer<DwarfContext, Dwarf> perform() {
+        return (ctx, dwarf) -> {
+            List<RunnerEvent> rl = (List) ctx.getEvents(RunnerEvent.class);
+            rl.forEach(e -> {
+                if (e instanceof StopRunnerEvent) {
+                    pos = -1;
+                    code = new ArrayList<>();
+                    error = false;
+                    id = null;
+                } else if (e instanceof StartRunnerEvent) {
+                    DecisionDescriptor descr = (((StartRunnerEvent) e).getDecision());
+                    id = descr.getId();
+                    code = descr.getCode();
+                    pos = 0;
+                    error = false;
+                    dwarf.getDecision().setStatus(id, PENDING);
+                }
+            });
+            left = Math.min(LiveCycle.MAX_STEPS, left + 8);
+            boolean ok = true;
+            while (!error && ok && pos >= 0 && pos < code.size()) {
+                ok = false;
+                RunnerCode op = RunnerCode.codeOf(this.code.get(pos));
+                if (op.getCost() <= left) {
+                    switch (op) {
+                        case UP:
+                            ok = ctx.move(dwarf, 0, 1);
+                            break;
+                        case DOWN:
+                            ok = ctx.move(dwarf, 0, -1);
+                            break;
+                        case LEFT:
+                            ok = ctx.move(dwarf, -1, 0);
+                            break;
+                        case RIGHT:
+                            ok = ctx.move(dwarf, 1, 0);
+                            break;
+                        case NOOP:
+                            ok = true;
+                            break;
+                        case EAT:
+                            if (ctx.eat(dwarf))
+                                dwarf.getEnergy().addFood();
+                            ok = true;
+                            break;
+                        default:
+                            throw new RuntimeException("unknown code " + op + " at pos" + pos);
+                    }
+                    //Logger.getLogger(getClass()).info("op "+op+" at "+pos+"/"+code.size()+ " is "+ok);
+                    if (ok) {
+                        pos++;
+                        left -= op.getCost();
+                        if (pos == code.size()) {
+                            dwarf.getDecision().setStatus(id, OK);
+                        }
+                    } else {
+                        error = true;
+                        dwarf.getDecision().setStatus(id, ERROR);
+                    }
+                } else {
+                    ok = false;
+                }
+            }
+        };
+    }
+}

+ 32 - 0
src/main/java/in/ocsf/frei/geld/core/model/aspects/RunnerCode.java

@@ -0,0 +1,32 @@
+package in.ocsf.frei.geld.core.model.aspects;/* kpmy 25.11.2017 */
+
+import java.util.Arrays;
+
+public enum RunnerCode {
+    LEFT("←", 1),
+    RIGHT("→", 1),
+    UP("↑", 1),
+    DOWN("↓", 1),
+    EAT("E", 1),
+    NOOP("", 1);
+
+    private int cost;
+    private String code;
+
+    RunnerCode(String code, int cost) {
+        this.code = code;
+        this.cost = cost;
+    }
+
+    public static RunnerCode codeOf(String code) {
+        return Arrays.stream(values()).filter(c -> c.code.equals(code)).findFirst().orElseThrow(RuntimeException::new);
+    }
+
+    public int getCost() {
+        return cost;
+    }
+
+    public String getCode() {
+        return code;
+    }
+}

+ 6 - 0
src/main/java/in/ocsf/frei/geld/core/model/aspects/RunnerEvent.java

@@ -0,0 +1,6 @@
+package in.ocsf.frei.geld.core.model.aspects;/* kpmy 25.11.2017 */
+
+import in.ocsf.frei.geld.core.model.ContextEvent;
+
+public interface RunnerEvent extends ContextEvent {
+}

+ 18 - 0
src/main/java/in/ocsf/frei/geld/core/model/aspects/StartRunnerEvent.java

@@ -0,0 +1,18 @@
+package in.ocsf.frei.geld.core.model.aspects;/* kpmy 25.11.2017 */
+
+public class StartRunnerEvent implements RunnerEvent {
+
+    private DecisionDescriptor decision;
+
+    public StartRunnerEvent(DecisionDescriptor decision) {
+        this.decision = decision;
+    }
+
+    public DecisionDescriptor getDecision() {
+        return decision;
+    }
+
+    public void setDecision(DecisionDescriptor decision) {
+        this.decision = decision;
+    }
+}

+ 10 - 0
src/main/java/in/ocsf/frei/geld/core/model/aspects/StopRunnerEvent.java

@@ -0,0 +1,10 @@
+package in.ocsf.frei.geld.core.model.aspects;/* kpmy 25.11.2017 */
+
+public class StopRunnerEvent implements RunnerEvent {
+
+    private DecisionDescriptor decision;
+
+    public StopRunnerEvent(DecisionDescriptor decision) {
+        this.decision = decision;
+    }
+}

+ 47 - 0
src/main/java/in/ocsf/frei/geld/core/model/aspects/TaskAspect.java

@@ -0,0 +1,47 @@
+package in.ocsf.frei.geld.core.model.aspects;/* kpmy 25.11.2017 */
+
+import in.ocsf.frei.geld.core.model.Dwarf;
+import in.ocsf.frei.geld.core.model.DwarfContext;
+import org.apache.commons.math3.complex.Complex;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.BiConsumer;
+import java.util.function.Function;
+
+public class TaskAspect implements DwarfDefaultAspect {
+
+    public static final DwarfTaskDescriptor REST = DwarfTaskDescriptor.getInstance(DwarfTask.REST, Complex.valueOf(0, 0.5));
+    private static Function<Dwarf, Complex> hungerF = (dwarf -> Complex.valueOf(dwarf.getFeelings().getHunger() / 100, 0.4));
+    //комплексное число обозначает противоречие приятного и полезного
+    private Map<DwarfTask, DwarfTaskDescriptor> queue;
+
+    public TaskAspect() {
+    }
+
+    public static TaskAspect getInstance() {
+        TaskAspect ret = new TaskAspect();
+        ret.queue = new HashMap<>();
+        return ret;
+    }
+
+    public Map<DwarfTask, DwarfTaskDescriptor> getQueue() {
+        return queue;
+    }
+
+    public void setQueue(Map<DwarfTask, DwarfTaskDescriptor> queue) {
+        this.queue = queue;
+    }
+
+    @Override
+    public BiConsumer<DwarfContext, Dwarf> perform() {
+        return (ctx, dwarf) -> {
+            if (queue.isEmpty()) queue.put(DwarfTask.REST, REST);
+            queue.put(DwarfTask.EAT, Optional.ofNullable(queue.get(DwarfTask.EAT)).map(t -> {
+                t.setComplexValue(hungerF.apply(dwarf));
+                return t;
+            }).orElse(DwarfTaskDescriptor.getInstance(DwarfTask.EAT, hungerF.apply(dwarf))));
+        };
+    }
+}

+ 60 - 0
src/main/java/in/ocsf/frei/geld/core/model/aspects/VisionAspect.java

@@ -0,0 +1,60 @@
+package in.ocsf.frei.geld.core.model.aspects;/* kpmy 25.11.2017 */
+
+import in.ocsf.frei.geld.core.model.Dwarf;
+import in.ocsf.frei.geld.core.model.DwarfContext;
+import in.ocsf.frei.geld.core.model.World;
+import in.ocsf.frei.geld.core.model.WorldObjectType;
+import org.apache.commons.lang3.tuple.MutablePair;
+import org.springframework.data.mongodb.core.mapping.DBRef;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+
+public class VisionAspect implements DwarfDefaultAspect {
+
+    private Map<String, MutablePair<WorldObjectType, Object>> frame;
+
+    @DBRef
+    private World.DwarfPoint self;
+
+    public VisionAspect() {
+    }
+
+    public static VisionAspect getInstance() {
+        VisionAspect ret = new VisionAspect();
+        ret.frame = new HashMap<>();
+        return ret;
+    }
+
+    public Map<String, MutablePair<WorldObjectType, Object>> getFrame() {
+        return frame;
+    }
+
+    public void setFrame(Map<String, MutablePair<WorldObjectType, Object>> frame) {
+        this.frame = frame;
+    }
+
+    @Override
+    public Consumer<Dwarf> skip() {
+        return (d) -> frame = new HashMap<>();
+    }
+
+    public World.DwarfPoint getSelf() {
+        return self;
+    }
+
+    public void setSelf(World.DwarfPoint self) {
+        this.self = self;
+    }
+
+    @Override
+    public BiConsumer<DwarfContext, Dwarf> perform() {
+        return (ctx, dwarf) -> {
+            self = ctx.getDwarfPosition(dwarf);
+            frame = ctx.getAllAround(self).stream().filter(s -> !s.getPoint().equals(self.getPoint())).collect(Collectors.toMap(s -> s.getPoint().toString(), World.Something::getRef, (same, key) -> same));
+        };
+    }
+}

+ 2 - 0
src/main/java/in/ocsf/frei/geld/core/repo/DwarfRepository.java

@@ -6,9 +6,11 @@ import in.ocsf.frei.geld.core.model.World;
 import org.bson.types.ObjectId;
 import org.springframework.data.mongodb.repository.MongoRepository;
 import org.springframework.data.querydsl.QueryDslPredicateExecutor;
+import org.springframework.data.rest.core.annotation.RepositoryRestResource;
 
 import java.util.stream.Stream;
 
+@RepositoryRestResource(collectionResourceRel = "dwarf", path = "dwarf")
 public interface DwarfRepository extends MongoRepository<Dwarf, ObjectId>, QueryDslPredicateExecutor<Dwarf> {
     Stream<Dwarf> findAllByStateInAndWorld(DwarfState[] states, World world);
 }

+ 4 - 4
src/main/java/in/ocsf/frei/geld/core/rest/DevController.java

@@ -8,6 +8,7 @@ import in.ocsf.frei.geld.core.repo.WorldRepository;
 import in.ocsf.frei.geld.core.service.LiveCycleService;
 import org.springframework.data.mongodb.core.MongoOperations;
 import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RestController;
 
 import javax.inject.Inject;
@@ -33,7 +34,7 @@ public class DevController {
     @Inject
     private MongoOperations mongo;
 
-    @RequestMapping("reset")
+    @RequestMapping(value = "reset", method = RequestMethod.POST)
     public void reset() {
         mongo.dropCollection(World.class);
         mongo.dropCollection(Dwarf.class);
@@ -41,9 +42,8 @@ public class DevController {
 
         World world = worldRepo.save(new World());
         loadMap(world, WorldMaps.HEAVEN);
-        for (int i = 0; i < 2; i++) {
-            Dwarf dwarf = new Dwarf();
-            dwarf.setWorld(world);
+        for (int i = 0; i < 1; i++) {
+            Dwarf dwarf = Dwarf.getInstance(world);
             dwarf.setName(DwarfNames.getRandomName());
             dwarf.setAge(18);
             dwarf.setDeath(Long.valueOf(50 + Math.round(25 * Math.random())).intValue());

+ 10 - 2
src/main/java/in/ocsf/frei/geld/core/service/DwarfService.java

@@ -1,6 +1,7 @@
 package in.ocsf.frei.geld.core.service;/* kpmy 15.11.2017 */
 
 import in.ocsf.frei.geld.core.model.*;
+import in.ocsf.frei.geld.core.model.aspects.DwarfAspect;
 import org.springframework.context.ApplicationContext;
 import org.springframework.stereotype.Service;
 
@@ -27,7 +28,7 @@ public class DwarfService {
                 aspect.perform().accept(context, dwarf);
             else
                 aspect.skip().accept(dwarf);
-            if (context.getConsequences().contains(SimpleConsequence.DEATH)) {
+            if (context.hasSimpleEvent(SimpleEvent.DEATH)) {
                 dwarf.setState(DwarfState.dead);
                 return;
             }
@@ -35,7 +36,14 @@ public class DwarfService {
     }
 
     private List<DwarfAspect> getAspects(Dwarf dwarf) {
-        return Stream.of(dwarf.getEnergy(), dwarf.getFeelings(), dwarf.getActivity(), dwarf.getVision())
+        return Stream.of(dwarf.getEnergy(),
+                dwarf.getFeelings(),
+                dwarf.getActivity(),
+                dwarf.getVision(),
+                dwarf.getTasks(),
+                dwarf.getManager(),
+                dwarf.getDecision(),
+                dwarf.getRunner())
                 .filter(Objects::nonNull)
                 .collect(Collectors.toList());
     }

+ 5 - 1
src/main/java/in/ocsf/frei/geld/core/service/LiveCycleService.java

@@ -38,7 +38,11 @@ public class LiveCycleService {
                 World world = worldRepo.findOne(World.defaultId);
                 List<Dwarf> dwarves = new ArrayList<>();
                 dwarves.addAll(dwarfRepo.findAllByStateInAndWorld(new DwarfState[]{DwarfState.old, DwarfState.mature, DwarfState.child}, world).collect(Collectors.toList()));
-                dwarves.parallelStream().peek(dwarf -> runDwarfHour(world, hour, dwarf)).forEach(dwarf -> dwarfRepo.save(dwarf));
+                try {
+                    dwarves.parallelStream().peek(dwarf -> runDwarfHour(world, hour, dwarf)).forEach(dwarf -> dwarfRepo.save(dwarf));
+                } catch (Exception e) {
+                    throw new RuntimeException(e);
+                }
                 world.setHour(world.getHour() + 1);
                 worldRepo.save(world);
             });

BIN
src/main/resources/static/2fcrYFNaTjcS6g4U3t-Y5ZjZjT5FdEJ140U2DJYC3mY.woff2


+ 16 - 1
src/main/resources/static/components/root.html

@@ -1,3 +1,18 @@
 <div>
-    <md-button ng-click="send()">SEND</md-button>
+    <md-button ng-click="reset()">
+        <md-icon>face</md-icon>
+        RESET
+    </md-button>
+    <table border="1">
+        <tr>
+            <th>ID</th>
+            <th>Name</th>
+        </tr>
+        <tr ng-repeat="d in dwarfList">
+            <td>{{d.age}}, {{d.day}}, {{d.hour}}</td>
+            <td>{{d.name}}</td>
+            <td>{{d.activity.active}}</td>
+            <td>{{d.energy.energy}}</td>
+        </tr>
+    </table>
 </div>

+ 17 - 2
src/main/resources/static/components/root.js

@@ -1,6 +1,21 @@
 angular.module("FreiG").controller("IndexController", function ($scope, $http, contextPath) {
 
-    $scope.send = function () {
-        $http.post(contextPath + "/api/new/ticket/", {from: "pk", to: "tmp", amount: 1});
+    var errorFn = function (e) {
+        console.log(e);
+    };
+
+    $scope.dwarfList = [];
+
+    var load = $scope.load = function () {
+        $http.get(contextPath + "/api/dwarf/").then(function (res) {
+            $scope.dwarfList = res.data._embedded.dwarf;
+        }, errorFn);
+        setTimeout(load, 1000);
+    };
+
+    setTimeout(load, 1000);
+
+    $scope.reset = function () {
+        $http.post(contextPath + "/dev/reset/", {});
     }
 });

BIN
src/main/resources/static/favicon.ico


+ 23 - 0
src/main/resources/static/fonts.css

@@ -0,0 +1,23 @@
+/* fallback */
+@font-face {
+    font-family: 'Material Icons';
+    font-style: normal;
+    font-weight: 400;
+    src: url(2fcrYFNaTjcS6g4U3t-Y5ZjZjT5FdEJ140U2DJYC3mY.woff2) format('woff2');
+}
+
+.material-icons {
+    font-family: 'Material Icons';
+    font-weight: normal;
+    font-style: normal;
+    font-size: 24px;
+    line-height: 1;
+    letter-spacing: normal;
+    text-transform: none;
+    display: inline-block;
+    white-space: nowrap;
+    word-wrap: normal;
+    direction: ltr;
+    -webkit-font-feature-settings: 'liga';
+    -webkit-font-smoothing: antialiased;
+}

+ 3 - 1
src/main/resources/static/index.html

@@ -8,8 +8,9 @@
     <link rel="stylesheet" href="bower_components/angular/angular-csp.css"/>
     <link rel="stylesheet" href="bower_components/angular-material/angular-material.css"/>
     <link rel="stylesheet" href="bower_components/roboto-fontface/css/roboto/roboto-fontface.css"/>
+    <link rel="stylesheet" href="fonts.css">
 </head>
-<body ui-view>
+<body>
 <script src="bower_components/underscore/underscore.js"></script>
 <script src="bower_components/jquery/dist/jquery.min.js"></script>
 
@@ -25,5 +26,6 @@
 <script src="components/app.js"></script>
 <script src="components/root.js"></script>
 <script src="components/route.js"></script>
+<div ui-view></div>
 </body>
 </html>