import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Random; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class AntFarm { static public class Food { private int _amount; Food(int amount) { _amount = amount; } synchronized int getAmount() { return _amount; } synchronized void addFood(int amount) { _amount += amount; } synchronized boolean removeFood() { if (_amount >= 1) { _amount--; return _amount != 0; } else return false; } } static public class Environment { private int _height; private int _width; public Environment(int height, int width) { _height = height; _width = width; } void update() { java.util.Random r = new java.util.Random(); Point pt = new Point(r.nextInt(_width), new java.util.Random().nextInt(_height)); if (map.containsKey(pt)) { map.get(pt).addFood(3 + r.nextInt(5)); } else { map.put(pt, new Food(3 + r.nextInt(5))); } } private ConcurrentHashMap map = new ConcurrentHashMap(); boolean hasFood(Point pt) { return map.containsKey(pt); } void dropFood(Point pt) { Food f = map.get(pt); if (f != null) f.addFood(1); else map.put(pt, new Food(1)); } void takeFood(Point pt) { map.compute(pt, (k, oldValue) -> !oldValue.removeFood() ? null : oldValue); //if (!map.get(pt).removeFood()) //map.remove(pt); } char displayPoint(Point pt) { return (hasFood(pt)) ? '#' : '_'; } int getFood(Point pt) { Food f = map.get(pt); return f != null ? f.getAmount() : 0; } } public class Ant { Ant(Environment env, Point nestLocation, Point location, int lifespan) { _env = env; _nestLocation = nestLocation; _location = location; _carrying = false; _lifespan = lifespan; _remainingSteps = 20; } private Environment _env; private Point _nestLocation; private int _remainingSteps; private int _lifespan; private Point _location; private boolean _carrying; void step() { if (_lifespan > 0) { if (_carrying) _location = _location.stepInDirection(_nestLocation); else if (_env.hasFood(_location) && !_location.equals(_nestLocation)) { _env.takeFood(_location); _carrying = true; } else { List neighbours = new ArrayList(_location.neighbours()); Random rand = new Random(); int index = rand.nextInt(neighbours.size()); _location = neighbours.get(index); _remainingSteps--; } System.out.println("I moved to " + _location); if (_location.equals(_nestLocation) && _carrying) { System.out.println("I'm in the nest."); _env.dropFood(_nestLocation); _carrying = false; _remainingSteps = 20; } _lifespan--; if (_lifespan == 0 || _remainingSteps == 0) { System.out.println("I died."); if (_carrying) { _env.dropFood(_location); _carrying = false; } } } } } public AntFarm(Environment env) { this.env = env; java.util.Random r = new java.util.Random(); nestLocation = new Point(r.nextInt(env._width), r.nextInt(env._height)); int total = 3 + r.nextInt(4); for (int i = 0; i < total; i++) { ants.add(new Ant(env, nestLocation, nestLocation, 99)); } executor = Executors.newFixedThreadPool(2); } private Environment env; private Point nestLocation; private ArrayList ants = new ArrayList(); private ExecutorService executor; public void run(int count) throws InterruptedException { while (count-- != 0) { display(); CountDownLatch awaitAllAnts = new CountDownLatch(ants.size()); for (Ant a : ants) { executor.execute(() -> { a.step(); awaitAllAnts.countDown(); }); } awaitAllAnts.await(); env.update(); } executor.shutdown(); System.out.println("Finished simulation."); } void display() { Set hs = new HashSet(); for (Ant a : ants) { hs.add(a._location); } for (int i = 0; i < env._width; i++) { for (int j = 0; j < env._height; j++) { Point pt = new Point(i, j); if (pt.equals(nestLocation)) System.out.print('N'); else if (hs.contains(pt)) System.out.print('A'); else System.out.print(env.displayPoint(pt)); } System.out.println(); } System.out.println("Nest food: " + env.getFood(nestLocation)); } public static void main(String [] args) throws InterruptedException { AntFarm af = new AntFarm(new Environment(30, 30)); af.run(100); } }