mirror of
https://github.com/Febbweiss/rabbits-vs-hunter.git
synced 2026-03-04 22:25:37 +00:00
Feature: initial commit
This commit is contained in:
23
README.md
Normal file
23
README.md
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# Rabbits vs Hunter
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
|
||||||
|
This projects manages a rabbit hunt.
|
||||||
|
It's possible to change some criteria such as trees, burrows and rabbits counts.
|
||||||
|
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
Using maven, just execute the following command :
|
||||||
|
```
|
||||||
|
mvn clean package
|
||||||
|
```
|
||||||
|
|
||||||
|
In the new _target_ folder, you will find the _rabbits-vs-hunter-[version]-jar-with-dependencies.jar_ jar file. This jar contains all dependencies.
|
||||||
|
|
||||||
|
## Running
|
||||||
|
|
||||||
|
Execute the built jar :
|
||||||
|
```
|
||||||
|
java -jar rabbits-vs-hunter-[version]-jar-with-dependencies.jar
|
||||||
|
```
|
||||||
63
pom.xml
Normal file
63
pom.xml
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>fr.pavnay</groupId>
|
||||||
|
<artifactId>rabbits-vs-hunter</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
<dependencies>
|
||||||
|
<!-- Tools -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-collections4</artifactId>
|
||||||
|
<version>4.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>log4j</groupId>
|
||||||
|
<artifactId>log4j</artifactId>
|
||||||
|
<version>1.2.17</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Testing -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>4.12</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>1.7</maven.compiler.source>
|
||||||
|
<maven.compiler.target>1.7</maven.compiler.target>
|
||||||
|
</properties>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
|
<version>3.1.0</version>
|
||||||
|
<configuration>
|
||||||
|
<descriptorRefs>
|
||||||
|
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||||
|
</descriptorRefs>
|
||||||
|
<archive>
|
||||||
|
<manifest>
|
||||||
|
<mainClass>fr.pavnay.rabbits.Main</mainClass>
|
||||||
|
</manifest>
|
||||||
|
</archive>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>make-assembly</id>
|
||||||
|
<!-- this is used for inheritance merges -->
|
||||||
|
<phase>package</phase>
|
||||||
|
<!-- bind to the packaging phase -->
|
||||||
|
<goals>
|
||||||
|
<goal>single</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
17
src/main/java/fr/pavnay/rabbits/Main.java
Normal file
17
src/main/java/fr/pavnay/rabbits/Main.java
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package fr.pavnay.rabbits;
|
||||||
|
|
||||||
|
import fr.pavnay.rabbits.ui.FormFrame;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* The main class to run
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class Main {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
new FormFrame();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
202
src/main/java/fr/pavnay/rabbits/engine/HuntEngine.java
Normal file
202
src/main/java/fr/pavnay/rabbits/engine/HuntEngine.java
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
package fr.pavnay.rabbits.engine;
|
||||||
|
|
||||||
|
import java.awt.Point;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import fr.pavnay.rabbits.model.Burrow;
|
||||||
|
import fr.pavnay.rabbits.model.Character;
|
||||||
|
import fr.pavnay.rabbits.model.Forest;
|
||||||
|
import fr.pavnay.rabbits.model.Hunter;
|
||||||
|
import fr.pavnay.rabbits.model.Rabbit;
|
||||||
|
import fr.pavnay.rabbits.model.enums.Speed;
|
||||||
|
import fr.pavnay.rabbits.model.enums.Status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* This class provides the hunt mechanisms like moving, shooting, etc...
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class HuntEngine {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(HuntEngine.class);
|
||||||
|
|
||||||
|
private Forest forest;
|
||||||
|
private Hunter hunter;
|
||||||
|
|
||||||
|
private int stepCount = 0;
|
||||||
|
private int lastShotStep = -4;
|
||||||
|
private Status status = Status.RUNNING;
|
||||||
|
|
||||||
|
public HuntEngine(Forest forest, Hunter hunter) {
|
||||||
|
this.forest = forest;
|
||||||
|
this.hunter = hunter;
|
||||||
|
}
|
||||||
|
public Forest getForest() {
|
||||||
|
return forest;
|
||||||
|
}
|
||||||
|
public Hunter getHunter() {
|
||||||
|
return hunter;
|
||||||
|
}
|
||||||
|
public Status getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The core engine method. To have a full hunt cycle, call this method in a loop still the HuntEngine.getStatus() returns a value different than RUNNING.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Status step() {
|
||||||
|
logger.debug("Step " + stepCount);
|
||||||
|
boolean hunterHasShot = false; // Only one shot per step
|
||||||
|
int stepSinceLastShot = stepCount - lastShotStep;
|
||||||
|
|
||||||
|
move(hunter);
|
||||||
|
|
||||||
|
Random rand = new Random();
|
||||||
|
for (Rabbit rabbit : forest.getRabbits() ) {
|
||||||
|
|
||||||
|
if( stepSinceLastShot > 3 && !rabbit.isScared() ) {
|
||||||
|
if( rabbit.getSpeed() > Speed.MEDIUM.getSpeed() ) {
|
||||||
|
rabbit.slowDown();
|
||||||
|
} else {
|
||||||
|
rabbit.setSpeed(rand.nextInt(Speed.RUNNING.getSpeed()));
|
||||||
|
}
|
||||||
|
} else if( stepSinceLastShot > 5 && rabbit.isScared() ) {
|
||||||
|
rabbit.setScared(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
move(rabbit);
|
||||||
|
|
||||||
|
boolean canShoot = !hunterHasShot && stepSinceLastShot > 5; // One shot per step and only 5 steps after the last shot.
|
||||||
|
|
||||||
|
if( canShoot && forest.canView( hunter, rabbit ) && hunter.isInRange(rabbit) ) {
|
||||||
|
hunterHasShot = true;
|
||||||
|
lastShotStep = stepCount;
|
||||||
|
if( hunter.shoot(rabbit) ) {
|
||||||
|
forest.killedRabbit(rabbit);
|
||||||
|
} else {
|
||||||
|
logger.info(String.format("Hunter missed a shot. %d ammos remaining", hunter.getAmmos()));
|
||||||
|
hunter.purchase(rabbit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A shot occurs, so rabbits must escape
|
||||||
|
if( hunterHasShot ) {
|
||||||
|
logger.debug("Escape from the hunter");
|
||||||
|
forest.escape(hunter);
|
||||||
|
}
|
||||||
|
|
||||||
|
stepCount++;
|
||||||
|
return updateStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The rabbit must choose a destination - Random, the last one or a burrow
|
||||||
|
*
|
||||||
|
* @param rabbit The rabbit to move
|
||||||
|
*/
|
||||||
|
protected void move( Rabbit rabbit ) {
|
||||||
|
Point location = rabbit.getLocation();
|
||||||
|
Point destination = rabbit.getDestination();
|
||||||
|
|
||||||
|
if( location.distance(destination) <= rabbit.getSpeed() ) {
|
||||||
|
List<Burrow> refuges = rabbit.getRefuges();
|
||||||
|
if( refuges.size() > 0 ) { // Purchased rabbit
|
||||||
|
Burrow refuge = refuges.get( refuges.size() -1 );
|
||||||
|
if( refuge.isFree() ) { // Only one rabbit per burrow
|
||||||
|
refuge.setFree(false);
|
||||||
|
forest.savedRabbit( rabbit );
|
||||||
|
} else {
|
||||||
|
Burrow burrow = forest.getNearestBurrow(hunter, rabbit); // Find another burrow
|
||||||
|
rabbit.setRefuge(burrow); // Keep in mind this burrow is full
|
||||||
|
rabbit.setDestination(burrow.getLocation());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setRandomDestination(rabbit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( rabbit.getDestination() != null ) {
|
||||||
|
go(rabbit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The hunter must choose a destination : the last one or a new randomized destination.
|
||||||
|
*
|
||||||
|
* @param hunter
|
||||||
|
*/
|
||||||
|
protected void move( Hunter hunter ) {
|
||||||
|
Point location = hunter.getLocation();
|
||||||
|
Point destination = hunter.getDestination();
|
||||||
|
|
||||||
|
if( location.distance(destination) < hunter.getSpeed() ) {
|
||||||
|
destination = setRandomDestination(hunter);
|
||||||
|
}
|
||||||
|
|
||||||
|
go(hunter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move the given character (Hunter or Rabbit)
|
||||||
|
*
|
||||||
|
* @param character
|
||||||
|
*/
|
||||||
|
protected void go(Character character) {
|
||||||
|
Point location = character.getLocation();
|
||||||
|
Point destination = character.getDestination();
|
||||||
|
|
||||||
|
double x = destination.getX() - location.getX();
|
||||||
|
double y = destination.getY() - location.getY();
|
||||||
|
|
||||||
|
double rate = character.getSpeed() / location.distance(destination);
|
||||||
|
|
||||||
|
double newX = Math.max(0, location.getX() + x * rate);
|
||||||
|
double newY = Math.max(0, location.getY() + y * rate);
|
||||||
|
Point newLocation = new Point((int) Math.min(newX, forest.getEdgeArea()), (int) Math.min(newY, forest.getEdgeArea()));
|
||||||
|
character.increaseDistance((int) location.distance(newLocation));
|
||||||
|
location.setLocation( newLocation );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* "Choose" a random destination for the given character (Hunter or Rabbit)
|
||||||
|
*
|
||||||
|
* @param character The character to move
|
||||||
|
* @return The new destination
|
||||||
|
*/
|
||||||
|
protected Point setRandomDestination(Character character) {
|
||||||
|
Random rand = new Random();
|
||||||
|
Point destination = new Point(rand.nextInt(forest.getEdgeArea()), rand.nextInt(forest.getEdgeArea()));
|
||||||
|
character.setDestination(destination);
|
||||||
|
|
||||||
|
return destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the hunt status
|
||||||
|
*
|
||||||
|
* @return The new Status
|
||||||
|
*/
|
||||||
|
protected Status updateStatus() {
|
||||||
|
if( forest.getRabbits().size() == 0 ) { // No more running rabbits, so the hunt ends
|
||||||
|
if( (forest.getRabbits().size() + forest.getSavedRabbits().size()) < forest.getDeadRabbits().size() ) { // Too many dead rabbit, the hunter wins
|
||||||
|
status = Status.HUNTER_WINS;
|
||||||
|
} else {
|
||||||
|
status = Status.RABBITS_WIN; // else, rabbits win
|
||||||
|
}
|
||||||
|
logger.info("Hunt ended : " + status);
|
||||||
|
} else if( hunter.getAmmos() == 0 ) { // No more ammos, rabbits win
|
||||||
|
status = Status.RABBITS_WIN;
|
||||||
|
logger.info("Hunt ended : " + status);
|
||||||
|
} else { // Hunt still running
|
||||||
|
status = Status.RUNNING;
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
36
src/main/java/fr/pavnay/rabbits/model/Burrow.java
Normal file
36
src/main/java/fr/pavnay/rabbits/model/Burrow.java
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
package fr.pavnay.rabbits.model;
|
||||||
|
|
||||||
|
import java.awt.Point;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* A rabbit burrow - Only one rabbit per burrow.
|
||||||
|
* Burrows are filled when a rabbit is purchased.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class Burrow {
|
||||||
|
|
||||||
|
private Point location;
|
||||||
|
private boolean free;
|
||||||
|
|
||||||
|
public Burrow( Point location ) {
|
||||||
|
this.location = location;
|
||||||
|
free = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Point getLocation() {
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
public void setFree(boolean free) {
|
||||||
|
this.free = free;
|
||||||
|
}
|
||||||
|
public boolean isFree() {
|
||||||
|
return free;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Burrow [location=" + location + ", free=" + free + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
18
src/main/java/fr/pavnay/rabbits/model/Character.java
Normal file
18
src/main/java/fr/pavnay/rabbits/model/Character.java
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package fr.pavnay.rabbits.model;
|
||||||
|
|
||||||
|
import java.awt.Point;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* An interface to manage hunter and rabbits in the same way.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface Character {
|
||||||
|
|
||||||
|
public Point getLocation();
|
||||||
|
public Point getDestination();
|
||||||
|
public void setDestination(Point destination);
|
||||||
|
|
||||||
|
public int getSpeed();
|
||||||
|
public void increaseDistance(int distance);
|
||||||
|
}
|
||||||
295
src/main/java/fr/pavnay/rabbits/model/Forest.java
Normal file
295
src/main/java/fr/pavnay/rabbits/model/Forest.java
Normal file
@@ -0,0 +1,295 @@
|
|||||||
|
package fr.pavnay.rabbits.model;
|
||||||
|
|
||||||
|
import java.awt.Point;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import fr.pavnay.rabbits.model.predicate.RangePredicate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* The main "entity" where rabbits live.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class Forest {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(Forest.class);
|
||||||
|
|
||||||
|
private List<Tree> trees = new ArrayList<Tree>();
|
||||||
|
private List<Rabbit> rabbits = new CopyOnWriteArrayList<Rabbit>();
|
||||||
|
private List<Rabbit> savedRabbits = new CopyOnWriteArrayList<Rabbit>();
|
||||||
|
private List<Rabbit> deadRabbits = new CopyOnWriteArrayList<Rabbit>();
|
||||||
|
private List<Burrow> burrows = new ArrayList<Burrow>();
|
||||||
|
|
||||||
|
private int edgeArea;
|
||||||
|
|
||||||
|
public Forest( int area, int treesCount, int burrowsCount, int rabbitsCount ) {
|
||||||
|
if( area <= 0 || area > 10) {
|
||||||
|
throw new IllegalArgumentException("Area must be between 1 and 10 ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if( treesCount <= 0 || treesCount > 1000) {
|
||||||
|
throw new IllegalArgumentException("Tree count must be between 1 and 1000 ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if( rabbitsCount <= 0 ) {
|
||||||
|
throw new IllegalArgumentException("Add some rabbits");
|
||||||
|
}
|
||||||
|
|
||||||
|
if( burrowsCount <= 0 || burrowsCount < rabbitsCount) {
|
||||||
|
throw new IllegalArgumentException("Add some burrows. Greater or equals than rabbits count.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
edgeArea = (int) Math.sqrt(area * 1000);
|
||||||
|
|
||||||
|
populate(treesCount, burrowsCount, rabbitsCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add trees, burrows and rabbits to the forest. These entities have random location (and rabbits random destination)
|
||||||
|
*
|
||||||
|
* @param treesCount Number of trees to create
|
||||||
|
* @param burrowsCount Number of burrows to create
|
||||||
|
* @param rabbitsCount Number of rabbits to create
|
||||||
|
*/
|
||||||
|
private void populate(int treesCount, int burrowsCount, int rabbitsCount) {
|
||||||
|
Random rand = new Random();
|
||||||
|
for( int i = 0; i < treesCount; i++ ) {
|
||||||
|
trees.add(new Tree(new Point(rand.nextInt(edgeArea), rand.nextInt(edgeArea))));
|
||||||
|
}
|
||||||
|
|
||||||
|
for( int i = 0; i < burrowsCount; i++ ) {
|
||||||
|
burrows.add(new Burrow(new Point(rand.nextInt(edgeArea), rand.nextInt(edgeArea))));
|
||||||
|
}
|
||||||
|
|
||||||
|
for( int i = 0; i < rabbitsCount; i++ ) {
|
||||||
|
Rabbit rabbit = new Rabbit(new Point(rand.nextInt(edgeArea), rand.nextInt(edgeArea)));
|
||||||
|
rabbit.setDestination(new Point(rand.nextInt(edgeArea), rand.nextInt(edgeArea)));
|
||||||
|
rabbits.add(rabbit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getEdgeArea() {
|
||||||
|
return edgeArea;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Rabbit> getRabbits() {
|
||||||
|
return rabbits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param hunter
|
||||||
|
* @return Rabbits in hunter range
|
||||||
|
*/
|
||||||
|
public List<Rabbit> getRabbitsInRange(Hunter hunter) {
|
||||||
|
return (List<Rabbit>) CollectionUtils.select(rabbits, new RangePredicate(hunter));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return Dead rabbits
|
||||||
|
*/
|
||||||
|
public List<Rabbit> getDeadRabbits() {
|
||||||
|
return deadRabbits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return Rabbits in burrows
|
||||||
|
*/
|
||||||
|
public List<Rabbit> getSavedRabbits() {
|
||||||
|
return savedRabbits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move a rabbit from "running" to "dead"
|
||||||
|
* @param rabbit
|
||||||
|
*/
|
||||||
|
public void killedRabbit(Rabbit rabbit) {
|
||||||
|
if( rabbits.remove(rabbit) ) {
|
||||||
|
logger.info("Poor rabbit... Killed...");
|
||||||
|
deadRabbits.add(rabbit);
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("Unable to kill a poor rabbit...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move a rabbit from "running" to "saved"
|
||||||
|
* @param rabbit
|
||||||
|
*/
|
||||||
|
public void savedRabbit(Rabbit rabbit) {
|
||||||
|
if( rabbits.remove(rabbit) ) {
|
||||||
|
logger.info("In a burrow... Rabbit saved");
|
||||||
|
rabbit.setDestination(null);
|
||||||
|
savedRabbits.add(rabbit);
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("Unable to save a poor rabbit...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Burrow> getBurrows() {
|
||||||
|
return burrows;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rabbits in hunter range must escape
|
||||||
|
* @param hunter
|
||||||
|
*/
|
||||||
|
public void escape(Hunter hunter) {
|
||||||
|
for( Rabbit rabbit : getRabbitsInRange(hunter) ) {
|
||||||
|
escape(hunter, rabbit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Choose a rabbit destination to escape. If the given rabbit is scared (the one on which the hunter shot), it must find a burrow.
|
||||||
|
* The others must go at the opposite of hunter location.
|
||||||
|
*
|
||||||
|
* @param hunter
|
||||||
|
* @param rabbit
|
||||||
|
*/
|
||||||
|
protected void escape( Hunter hunter, Rabbit rabbit ) {
|
||||||
|
Point target = null;
|
||||||
|
if( rabbit.isScared() ) {
|
||||||
|
logger.debug("Rabbit's searching a burrow");
|
||||||
|
Burrow refuge = getNearestBurrow(hunter, rabbit);
|
||||||
|
rabbit.setRefuge(refuge);
|
||||||
|
} else {
|
||||||
|
logger.debug("Go away from the hunter");
|
||||||
|
// Hunter -> Rabbit vector
|
||||||
|
double a = rabbit.getLocation().getX() - hunter.getLocation().getX();
|
||||||
|
double b = rabbit.getLocation().getY() - hunter.getLocation().getY();
|
||||||
|
|
||||||
|
// Keep in forest
|
||||||
|
double x = Math.max(0, rabbit.getLocation().getX() + a);
|
||||||
|
double y = Math.max(0, rabbit.getLocation().getY() + b);
|
||||||
|
target = new Point((int) Math.min(x, edgeArea), (int) Math.min(y, edgeArea));
|
||||||
|
rabbit.setDestination(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute 2 nearest burrows. One with back to the hunter and another more safe. The last one is preferred
|
||||||
|
*
|
||||||
|
* @param hunter
|
||||||
|
* @param rabbit
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Burrow getNearestBurrow(Hunter hunter, Rabbit rabbit) {
|
||||||
|
logger.debug("Searching the nearest burrow");
|
||||||
|
double distance = Double.MAX_VALUE, worthDistance = Double.MAX_VALUE;
|
||||||
|
Burrow nearest = null, worthNearest = null;
|
||||||
|
|
||||||
|
for( Burrow burrow : burrows ) {
|
||||||
|
if( rabbit.getRefuges().contains(burrow) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
double tmpDistance = burrow.getLocation().distance(rabbit.getLocation());
|
||||||
|
double dotProduct = dotProduct(hunter.getLocation(), rabbit.getLocation(), burrow.getLocation());
|
||||||
|
if( dotProduct <= 0 && tmpDistance < distance ) {
|
||||||
|
distance = tmpDistance;
|
||||||
|
nearest = burrow;
|
||||||
|
}
|
||||||
|
else if( dotProduct > 0 && tmpDistance < worthDistance ) { // Back to the hunter
|
||||||
|
worthDistance = tmpDistance;
|
||||||
|
worthNearest = burrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return distance <= worthDistance ? nearest : worthNearest;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Tree> getTrees() {
|
||||||
|
return trees;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A rabbit is viewed when there are no trees between the hunter and it.
|
||||||
|
*
|
||||||
|
* @param hunter
|
||||||
|
* @param rabbit
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean canView(Hunter hunter, Rabbit rabbit) {
|
||||||
|
for( Tree tree : trees ) {
|
||||||
|
if( isBetween(hunter.getLocation(), rabbit.getLocation(), tree.getLocation())) {
|
||||||
|
logger.debug("Rabbit is hidden");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final int EPSILON = 5;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a tree is between a rabbit and the hunter.
|
||||||
|
*
|
||||||
|
* @param hunter
|
||||||
|
* @param rabbit
|
||||||
|
* @param tree
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected boolean isBetween(Point hunter, Point rabbit, Point tree) {
|
||||||
|
double crossproduct = (tree.getY() - hunter.getY()) * (rabbit.getX() - hunter.getX()) - (tree.getX() - hunter.getX()) * (rabbit.getY() - hunter.getY());
|
||||||
|
if (Math.abs(crossproduct) > EPSILON ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
double dotproduct = dotProduct(hunter, rabbit, tree); // Tree is far away
|
||||||
|
if ( dotproduct < 0 ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
double squaredlengthba = (rabbit.getX()- hunter.getX())*(rabbit.getX() - hunter.getX()) + (rabbit.getY() - hunter.getY())*(rabbit.getY() - hunter.getY());
|
||||||
|
if ( dotproduct > squaredlengthba) { // Tree is too far
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dotProduct to know if the tree is between the hunter and the rabbit.
|
||||||
|
*
|
||||||
|
* @param hunter
|
||||||
|
* @param rabbit
|
||||||
|
* @param tree
|
||||||
|
* @return If positive, the tree is between.
|
||||||
|
*/
|
||||||
|
private double dotProduct(Point hunter, Point rabbit, Point tree) {
|
||||||
|
return (tree.getX() - hunter.getX()) * (rabbit.getX() - hunter.getX()) + (tree.getY() - hunter.getY())*(rabbit.getY() - hunter.getY());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void printStats() {
|
||||||
|
logger.debug("Running rabbits");
|
||||||
|
printRabbits(rabbits);
|
||||||
|
logger.debug("Saved rabbits");
|
||||||
|
printRabbits(savedRabbits);
|
||||||
|
logger.debug("Dead rabbits");
|
||||||
|
printRabbits(deadRabbits);
|
||||||
|
}
|
||||||
|
private void printRabbits(List<Rabbit> rabbits) {
|
||||||
|
for( Rabbit rabbit : rabbits ) {
|
||||||
|
logger.debug(rabbit);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Forest [trees=" + trees + ", rabbits=" + rabbits + ", burrows=" + burrows + ", edgeArea=" + edgeArea
|
||||||
|
+ "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
129
src/main/java/fr/pavnay/rabbits/model/Hunter.java
Normal file
129
src/main/java/fr/pavnay/rabbits/model/Hunter.java
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
package fr.pavnay.rabbits.model;
|
||||||
|
|
||||||
|
import java.awt.Point;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import fr.pavnay.rabbits.model.enums.Speed;
|
||||||
|
|
||||||
|
public class Hunter implements Character {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(Hunter.class);
|
||||||
|
|
||||||
|
private final static int INITIAL_AMMOS = 10;
|
||||||
|
|
||||||
|
private int ammos = INITIAL_AMMOS;
|
||||||
|
private int hungryLevel = 0;
|
||||||
|
private int distance = 0;
|
||||||
|
private Point location;
|
||||||
|
private int range;
|
||||||
|
private int speed;
|
||||||
|
|
||||||
|
private Point destination;
|
||||||
|
|
||||||
|
public Hunter( Point location, int range ) {
|
||||||
|
this.location = location;
|
||||||
|
this.range = range;
|
||||||
|
this.speed = Speed.MEDIUM.getSpeed();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAmmos() {
|
||||||
|
return ammos;
|
||||||
|
}
|
||||||
|
public void setAmmos(int ammos) {
|
||||||
|
this.ammos = ammos;
|
||||||
|
}
|
||||||
|
public int getHungryLevel() {
|
||||||
|
return hungryLevel;
|
||||||
|
}
|
||||||
|
public void setHungryLevel(int hungryLevel) {
|
||||||
|
this.hungryLevel = hungryLevel;
|
||||||
|
}
|
||||||
|
public int getDistance() {
|
||||||
|
return distance;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public Point getLocation() {
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public Point getDestination() {
|
||||||
|
return destination;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void setDestination(Point destination) {
|
||||||
|
this.destination = destination;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public int getSpeed() {
|
||||||
|
return speed;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Increasing the walked distance increases the hungry level
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void increaseDistance(int distance) {
|
||||||
|
this.distance += distance;
|
||||||
|
setHungryLevel(Math.min(10, (int) (this.distance / 15)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to shoot a rabbit
|
||||||
|
*
|
||||||
|
* @param rabbit
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean shoot(Rabbit rabbit) {
|
||||||
|
if( ammos == 0 ) {
|
||||||
|
logger.info("Click... No more ammos");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
double rate = getAccuracyRate(rabbit);
|
||||||
|
ammos--;
|
||||||
|
return Math.random() < rate; // If the random value is less than the computed accuracy, the shot is good
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The hunter finds a rabbit. He goes to its last position.
|
||||||
|
*
|
||||||
|
* @param rabbit
|
||||||
|
*/
|
||||||
|
public void purchase(Rabbit rabbit) {
|
||||||
|
rabbit.purchased();
|
||||||
|
destination = rabbit.getLocation();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accuracy depends to the distance with the target, the number of leaving ammos and the hungry level.
|
||||||
|
*
|
||||||
|
* @param rabbit
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected double getAccuracyRate(Rabbit rabbit) {
|
||||||
|
double rate = 1 - getLocation().distance(rabbit.getLocation()) / range;
|
||||||
|
|
||||||
|
rate -= 0.005 * (INITIAL_AMMOS - ammos);
|
||||||
|
rate -= 0.01 * hungryLevel;
|
||||||
|
|
||||||
|
return rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The given rabbit is in range if the distance between the hunter and the rabbit is less than the hunter range.
|
||||||
|
*
|
||||||
|
* @param rabbit
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean isInRange(Rabbit rabbit) {
|
||||||
|
logger.debug(location.distance(rabbit.getLocation()) + "<=" + range);
|
||||||
|
return location.distance(rabbit.getLocation()) <= range;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Hunter [ammos=" + ammos + ", hungryLevel=" + hungryLevel + ", distance=" + distance + ", location="
|
||||||
|
+ location + ", range=" + range + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
91
src/main/java/fr/pavnay/rabbits/model/Rabbit.java
Normal file
91
src/main/java/fr/pavnay/rabbits/model/Rabbit.java
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
package fr.pavnay.rabbits.model;
|
||||||
|
|
||||||
|
import java.awt.Point;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import fr.pavnay.rabbits.model.enums.Color;
|
||||||
|
import fr.pavnay.rabbits.model.enums.Speed;
|
||||||
|
|
||||||
|
public class Rabbit implements Character {
|
||||||
|
|
||||||
|
private Point location;
|
||||||
|
private int speed;
|
||||||
|
private Color color;
|
||||||
|
private int distance;
|
||||||
|
|
||||||
|
private Point destination;
|
||||||
|
|
||||||
|
private List<Burrow> refuges = new ArrayList<Burrow>();
|
||||||
|
private boolean scared;
|
||||||
|
|
||||||
|
public Rabbit(Point location) {
|
||||||
|
this.color = Math.random() < 0.5 ? Color.BROWN : Color.WHITE;
|
||||||
|
this.location = location;
|
||||||
|
speed = Speed.SLOW.getSpeed();
|
||||||
|
distance = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Point getLocation() {
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public int getSpeed() {
|
||||||
|
return speed;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void increaseDistance(int distance) {
|
||||||
|
this.distance += distance;
|
||||||
|
}
|
||||||
|
public void setSpeed(int speed) {
|
||||||
|
this.speed = speed;
|
||||||
|
}
|
||||||
|
public Color getColor() {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
public int getDistance() {
|
||||||
|
return distance;
|
||||||
|
}
|
||||||
|
public boolean isScared() {
|
||||||
|
return scared;
|
||||||
|
}
|
||||||
|
public void setScared(boolean scared) {
|
||||||
|
this.scared = scared;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void setDestination(Point destination) {
|
||||||
|
this.destination = destination;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public Point getDestination() {
|
||||||
|
return destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The rabbit finds a burrow. So it keeps in mind its location and to go it.
|
||||||
|
*
|
||||||
|
* @param refuge
|
||||||
|
*/
|
||||||
|
public void setRefuge(Burrow refuge) {
|
||||||
|
this.refuges.add( refuge );
|
||||||
|
destination = refuge.getLocation();
|
||||||
|
}
|
||||||
|
public List<Burrow> getRefuges() {
|
||||||
|
return refuges;
|
||||||
|
}
|
||||||
|
public void slowDown() {
|
||||||
|
speed = Math.max(0, speed - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void purchased() {
|
||||||
|
scared = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Rabbit [location=" + location + ", speed=" + speed + ", color=" + color + ", distance=" + distance
|
||||||
|
+ "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
22
src/main/java/fr/pavnay/rabbits/model/Tree.java
Normal file
22
src/main/java/fr/pavnay/rabbits/model/Tree.java
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
package fr.pavnay.rabbits.model;
|
||||||
|
|
||||||
|
import java.awt.Point;
|
||||||
|
|
||||||
|
public class Tree {
|
||||||
|
|
||||||
|
private Point location;
|
||||||
|
|
||||||
|
public Tree( Point location ) {
|
||||||
|
this.location = location;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Point getLocation() {
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Tree [location=" + location + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
22
src/main/java/fr/pavnay/rabbits/model/enums/Color.java
Normal file
22
src/main/java/fr/pavnay/rabbits/model/enums/Color.java
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
package fr.pavnay.rabbits.model.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* An utility enum to give color to rabbits
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public enum Color {
|
||||||
|
|
||||||
|
WHITE(java.awt.Color.WHITE),
|
||||||
|
BROWN(new java.awt.Color(149, 86, 40));
|
||||||
|
|
||||||
|
private java.awt.Color color;
|
||||||
|
|
||||||
|
private Color( java.awt.Color color) {
|
||||||
|
this.color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public java.awt.Color getColor() {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
}
|
||||||
25
src/main/java/fr/pavnay/rabbits/model/enums/Speed.java
Normal file
25
src/main/java/fr/pavnay/rabbits/model/enums/Speed.java
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package fr.pavnay.rabbits.model.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* An utility enum to give some default speeds
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public enum Speed {
|
||||||
|
|
||||||
|
STOPPED(0),
|
||||||
|
SLOW(1),
|
||||||
|
MEDIUM(5),
|
||||||
|
RUNNING(10);
|
||||||
|
|
||||||
|
private int speed;
|
||||||
|
|
||||||
|
private Speed(int speed) {
|
||||||
|
this.speed = speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSpeed() {
|
||||||
|
return speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
18
src/main/java/fr/pavnay/rabbits/model/enums/Status.java
Normal file
18
src/main/java/fr/pavnay/rabbits/model/enums/Status.java
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package fr.pavnay.rabbits.model.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* The hunt status
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public enum Status {
|
||||||
|
|
||||||
|
RUNNING,
|
||||||
|
HUNTER_WINS,
|
||||||
|
RABBITS_WIN;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return name().charAt(0) + name().substring(1).toLowerCase().replace('_', ' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package fr.pavnay.rabbits.model.predicate;
|
||||||
|
|
||||||
|
import org.apache.commons.collections4.Predicate;
|
||||||
|
|
||||||
|
import fr.pavnay.rabbits.model.Hunter;
|
||||||
|
import fr.pavnay.rabbits.model.Rabbit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* An utility class to check if a rabbit is in the hunter range
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class RangePredicate implements Predicate<Rabbit> {
|
||||||
|
|
||||||
|
private Hunter hunter;
|
||||||
|
|
||||||
|
public RangePredicate(Hunter hunter) {
|
||||||
|
this.hunter = hunter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean evaluate(Rabbit rabbit) {
|
||||||
|
return hunter.isInRange(rabbit);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
115
src/main/java/fr/pavnay/rabbits/ui/FormFrame.java
Normal file
115
src/main/java/fr/pavnay/rabbits/ui/FormFrame.java
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
package fr.pavnay.rabbits.ui;
|
||||||
|
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.GridBagLayout;
|
||||||
|
import java.awt.Point;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
import java.beans.PropertyChangeEvent;
|
||||||
|
import java.beans.PropertyChangeListener;
|
||||||
|
import java.text.NumberFormat;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import javax.swing.JButton;
|
||||||
|
import javax.swing.JFormattedTextField;
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JOptionPane;
|
||||||
|
import javax.swing.text.NumberFormatter;
|
||||||
|
|
||||||
|
import fr.pavnay.rabbits.engine.HuntEngine;
|
||||||
|
import fr.pavnay.rabbits.model.Forest;
|
||||||
|
import fr.pavnay.rabbits.model.Hunter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* The entry point in which forest area, trees, burrows and rabbit numbers are set.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class FormFrame extends JFrame implements ActionListener, PropertyChangeListener {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 4594334659003442873L;
|
||||||
|
|
||||||
|
private JFormattedTextField areaInput; // Only number with specificities (min, max)
|
||||||
|
private JFormattedTextField treeInput;
|
||||||
|
private JFormattedTextField rabbitInput;
|
||||||
|
private JFormattedTextField burrowInput;
|
||||||
|
|
||||||
|
private JButton validateBtn;
|
||||||
|
|
||||||
|
public FormFrame() {
|
||||||
|
setTitle("Rabbits vs Hunter");
|
||||||
|
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||||
|
|
||||||
|
setLayout(new GridBagLayout());
|
||||||
|
UiUtils.add(this, new JLabel("Area"), 0, 0, 1, 1);
|
||||||
|
areaInput = new JFormattedTextField(getFormatter(1, 10));
|
||||||
|
areaInput.setValue(10);
|
||||||
|
areaInput.addActionListener(this);
|
||||||
|
UiUtils.add(this, areaInput, 1, 0, 1, 1);
|
||||||
|
UiUtils.add(this, new JLabel("Trees"), 0, 1, 1, 1);
|
||||||
|
|
||||||
|
treeInput = new JFormattedTextField(getFormatter(0, 300));
|
||||||
|
treeInput.setValue(20);
|
||||||
|
treeInput.addActionListener(this);
|
||||||
|
UiUtils.add(this, treeInput, 1, 1, 1, 1);
|
||||||
|
UiUtils.add(this, new JLabel("Rabbits"), 0, 2, 1, 1);
|
||||||
|
rabbitInput = new JFormattedTextField(getFormatter(1, 20));
|
||||||
|
rabbitInput.setValue(5);
|
||||||
|
rabbitInput.addActionListener(this);
|
||||||
|
UiUtils.add(this, rabbitInput, 1, 2, 1, 1);
|
||||||
|
UiUtils.add(this, new JLabel("Burrows"), 0, 3, 1, 1);
|
||||||
|
burrowInput = new JFormattedTextField(getFormatter(1, 20));
|
||||||
|
burrowInput.setValue(10);
|
||||||
|
burrowInput.addPropertyChangeListener(this);
|
||||||
|
UiUtils.add(this, burrowInput, 1, 3, 1, 1);
|
||||||
|
|
||||||
|
validateBtn = new JButton("Validate");
|
||||||
|
validateBtn.addActionListener(this);
|
||||||
|
|
||||||
|
UiUtils.add(this, validateBtn, 0, 4, 2, 1);
|
||||||
|
pack();
|
||||||
|
setLocationRelativeTo(null);
|
||||||
|
setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private NumberFormatter getFormatter( int min, int max) {
|
||||||
|
NumberFormat format = NumberFormat.getInstance();
|
||||||
|
NumberFormatter formatter = new NumberFormatter(format);
|
||||||
|
formatter.setValueClass(Integer.class);
|
||||||
|
formatter.setMinimum(min);
|
||||||
|
formatter.setMaximum(max);
|
||||||
|
formatter.setAllowsInvalid(false);
|
||||||
|
return formatter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent event) {
|
||||||
|
if( Integer.parseInt(burrowInput.getText()) < Integer.parseInt(rabbitInput.getText()) ) {
|
||||||
|
JOptionPane.showMessageDialog(this, "Add some burrows. Greater or equals than rabbits count.", "Error", JOptionPane.ERROR_MESSAGE);
|
||||||
|
} else {
|
||||||
|
Forest forest = new Forest(Integer.parseInt(areaInput.getText()), Integer.parseInt(treeInput.getText()),
|
||||||
|
Integer.parseInt(burrowInput.getText()), Integer.parseInt(rabbitInput.getText()));
|
||||||
|
|
||||||
|
Random rand = new Random();
|
||||||
|
Hunter hunter = new Hunter(new Point(rand.nextInt(forest.getEdgeArea()), rand.nextInt(forest.getEdgeArea())), 20);
|
||||||
|
hunter.setDestination(new Point(rand.nextInt(forest.getEdgeArea()), rand.nextInt(forest.getEdgeArea())));
|
||||||
|
HuntEngine engine = new HuntEngine(forest, hunter);
|
||||||
|
|
||||||
|
new MainFrame(engine);
|
||||||
|
dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void propertyChange(PropertyChangeEvent arg0) {
|
||||||
|
validateBtn.setEnabled(!"".equals(areaInput.getText()) && !"".equals(treeInput.getText())
|
||||||
|
&& !"".equals(rabbitInput.getText()) && !"".equals(burrowInput.getText()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dimension getPreferredSize() {
|
||||||
|
return new Dimension(250, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
98
src/main/java/fr/pavnay/rabbits/ui/HuntWorker.java
Normal file
98
src/main/java/fr/pavnay/rabbits/ui/HuntWorker.java
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
package fr.pavnay.rabbits.ui;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.swing.SwingWorker;
|
||||||
|
|
||||||
|
import org.apache.log4j.AppenderSkeleton;
|
||||||
|
import org.apache.log4j.Level;
|
||||||
|
import org.apache.log4j.LogManager;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
import org.apache.log4j.spi.LoggingEvent;
|
||||||
|
|
||||||
|
import fr.pavnay.rabbits.engine.HuntEngine;
|
||||||
|
import fr.pavnay.rabbits.model.enums.Status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* This worker provides the loop to play HuntEngine.step() until the status is different to RUNNING
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class HuntWorker extends SwingWorker<Status, String> {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(HuntWorker.class);
|
||||||
|
|
||||||
|
public final static long SLEEP_TIME = 500;
|
||||||
|
|
||||||
|
private HuntEngine engine;
|
||||||
|
private MainFrame mainFrame;
|
||||||
|
|
||||||
|
public HuntWorker(HuntEngine engine, MainFrame mainFrame ) {
|
||||||
|
this.engine = engine;
|
||||||
|
this.mainFrame = mainFrame;
|
||||||
|
HuntLogAppender appender = new HuntLogAppender(this);
|
||||||
|
LogManager.getLogger("fr.pavnay.rabbits").addAppender(appender);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void appendLog(String log) {
|
||||||
|
publish(log);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides some hunt event from logs to UI
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void process(List<String> logs) {
|
||||||
|
for(String log : logs) {
|
||||||
|
mainFrame.report(log);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Status doInBackground() throws Exception {
|
||||||
|
Status status = engine.getStatus();
|
||||||
|
try {
|
||||||
|
while( status == Status.RUNNING ) {
|
||||||
|
status = engine.step();
|
||||||
|
Thread.sleep(SLEEP_TIME);
|
||||||
|
}
|
||||||
|
}catch( Exception e) {
|
||||||
|
logger.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
logger.debug("Hunt ended : " + engine.getStatus());
|
||||||
|
return engine.getStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void done() {
|
||||||
|
super.done();
|
||||||
|
logger.debug("Done - " + engine.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* A log appender to retrieve hunt logs and give them to UI.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class HuntLogAppender extends AppenderSkeleton {
|
||||||
|
private final HuntWorker worker;
|
||||||
|
|
||||||
|
public HuntLogAppender( HuntWorker slurperWorker) {
|
||||||
|
this.worker = slurperWorker;
|
||||||
|
}
|
||||||
|
protected void append(LoggingEvent event)
|
||||||
|
{
|
||||||
|
if(event.getLevel().equals(Level.INFO)){
|
||||||
|
worker.appendLog(event.getMessage().toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void close()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public boolean requiresLayout()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
114
src/main/java/fr/pavnay/rabbits/ui/MainFrame.java
Normal file
114
src/main/java/fr/pavnay/rabbits/ui/MainFrame.java
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
package fr.pavnay.rabbits.ui;
|
||||||
|
|
||||||
|
import java.awt.BorderLayout;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
import java.beans.PropertyChangeEvent;
|
||||||
|
import java.beans.PropertyChangeListener;
|
||||||
|
|
||||||
|
import javax.swing.BorderFactory;
|
||||||
|
import javax.swing.Box;
|
||||||
|
import javax.swing.BoxLayout;
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JScrollPane;
|
||||||
|
import javax.swing.SwingWorker;
|
||||||
|
import javax.swing.Timer;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import fr.pavnay.rabbits.engine.HuntEngine;
|
||||||
|
import fr.pavnay.rabbits.ui.panel.Canvas;
|
||||||
|
import fr.pavnay.rabbits.ui.panel.CanvasLegend;
|
||||||
|
import fr.pavnay.rabbits.ui.panel.CharacterPanel;
|
||||||
|
import fr.pavnay.rabbits.ui.panel.LogPanel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* The frame to see the hunt.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class MainFrame extends JFrame implements PropertyChangeListener, ActionListener {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -5070100141993068939L;
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(MainFrame.class);
|
||||||
|
|
||||||
|
private HuntEngine engine;
|
||||||
|
|
||||||
|
private Timer timer; // Timer used to refresh UI periodically
|
||||||
|
|
||||||
|
private JPanel canvas; // The hunt panel
|
||||||
|
private CharacterPanel characterPanel; // Characters stats panel
|
||||||
|
private LogPanel logPanel; // Hunt event panel
|
||||||
|
private JLabel statusLabel; // Hunt status
|
||||||
|
|
||||||
|
private HuntWorker worker;
|
||||||
|
|
||||||
|
public MainFrame( HuntEngine engine ) {
|
||||||
|
setTitle("Rabbits vs Hunter");
|
||||||
|
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||||
|
|
||||||
|
setLayout(new BorderLayout());
|
||||||
|
|
||||||
|
this.engine = engine;
|
||||||
|
|
||||||
|
JPanel statusPanel = new JPanel();
|
||||||
|
statusPanel.add(new JLabel("Status :"));
|
||||||
|
statusLabel = new JLabel(engine.getStatus().toString());
|
||||||
|
statusPanel.add(statusLabel);
|
||||||
|
add(statusPanel, BorderLayout.NORTH);
|
||||||
|
|
||||||
|
canvas = new Canvas(engine.getForest(), engine.getHunter());
|
||||||
|
timer = new Timer((int) HuntWorker.SLEEP_TIME, this);
|
||||||
|
add(canvas, BorderLayout.CENTER);
|
||||||
|
|
||||||
|
characterPanel = new CharacterPanel(engine.getHunter(), engine.getForest());
|
||||||
|
logPanel = new LogPanel();
|
||||||
|
|
||||||
|
int VERT_GAP = 10;
|
||||||
|
int EB_GAP = 5;
|
||||||
|
JPanel sidePanel = new JPanel();
|
||||||
|
sidePanel.setBorder(BorderFactory.createEmptyBorder(EB_GAP, EB_GAP, EB_GAP, EB_GAP));
|
||||||
|
sidePanel.setLayout(new BoxLayout(sidePanel, BoxLayout.PAGE_AXIS));
|
||||||
|
sidePanel.add(characterPanel);
|
||||||
|
sidePanel.add(Box.createVerticalStrut(VERT_GAP));
|
||||||
|
sidePanel.add(Box.createVerticalStrut(VERT_GAP));
|
||||||
|
sidePanel.add(new JScrollPane(logPanel));
|
||||||
|
add(sidePanel, BorderLayout.EAST);
|
||||||
|
|
||||||
|
add( new CanvasLegend(engine.getForest()), BorderLayout.SOUTH );
|
||||||
|
|
||||||
|
worker = new HuntWorker(engine, this);
|
||||||
|
worker.addPropertyChangeListener(this);
|
||||||
|
worker.execute();
|
||||||
|
timer.start();
|
||||||
|
|
||||||
|
pack();
|
||||||
|
setLocationRelativeTo(null);
|
||||||
|
setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void propertyChange(PropertyChangeEvent event) {
|
||||||
|
if ("state".equals(event.getPropertyName()) && SwingWorker.StateValue.DONE == event.getNewValue()) { // Worker ends
|
||||||
|
statusLabel.setText(engine.getStatus().toString());
|
||||||
|
statusLabel.repaint();
|
||||||
|
|
||||||
|
logger.debug(engine.getHunter());
|
||||||
|
engine.getForest().printStats();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void actionPerformed(ActionEvent event) {
|
||||||
|
if(event.getSource()==timer){
|
||||||
|
canvas.repaint();
|
||||||
|
characterPanel.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void report(String log) {
|
||||||
|
logPanel.addLog(log);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
40
src/main/java/fr/pavnay/rabbits/ui/UiUtils.java
Normal file
40
src/main/java/fr/pavnay/rabbits/ui/UiUtils.java
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package fr.pavnay.rabbits.ui;
|
||||||
|
|
||||||
|
import java.awt.Container;
|
||||||
|
import java.awt.GridBagConstraints;
|
||||||
|
import java.awt.Insets;
|
||||||
|
|
||||||
|
import javax.swing.JComponent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* An utility class for UI
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class UiUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a component in a container with a GridBagLayout
|
||||||
|
*
|
||||||
|
* @param container
|
||||||
|
* @param component
|
||||||
|
* @param x
|
||||||
|
* @param y
|
||||||
|
* @param w
|
||||||
|
* @param h
|
||||||
|
*/
|
||||||
|
public static void add(Container container, JComponent component, int x, int y,
|
||||||
|
int w, int h) {
|
||||||
|
GridBagConstraints bagConstraints = new GridBagConstraints();
|
||||||
|
bagConstraints.gridx = x;
|
||||||
|
bagConstraints.gridy = y;
|
||||||
|
bagConstraints.gridwidth = w;
|
||||||
|
bagConstraints.gridheight = h;
|
||||||
|
bagConstraints.anchor = (x == 0) ? GridBagConstraints.EAST
|
||||||
|
: GridBagConstraints.WEST;
|
||||||
|
bagConstraints.fill = (x == 0) ? GridBagConstraints.BOTH
|
||||||
|
: GridBagConstraints.HORIZONTAL;
|
||||||
|
bagConstraints.insets = new Insets(5, 5, 5, 5);
|
||||||
|
container.add(component, bagConstraints);
|
||||||
|
}
|
||||||
|
}
|
||||||
71
src/main/java/fr/pavnay/rabbits/ui/panel/Canvas.java
Normal file
71
src/main/java/fr/pavnay/rabbits/ui/panel/Canvas.java
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
package fr.pavnay.rabbits.ui.panel;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.Graphics;
|
||||||
|
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
|
||||||
|
import fr.pavnay.rabbits.model.Burrow;
|
||||||
|
import fr.pavnay.rabbits.model.Forest;
|
||||||
|
import fr.pavnay.rabbits.model.Hunter;
|
||||||
|
import fr.pavnay.rabbits.model.Rabbit;
|
||||||
|
import fr.pavnay.rabbits.model.Tree;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* This class draws all hunt elements : trees, burrows, hunter and rabbits
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class Canvas extends JPanel {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 4209640358977009595L;
|
||||||
|
|
||||||
|
protected static int RATE = 5;
|
||||||
|
protected static int ITEM_RATIO = 2;
|
||||||
|
|
||||||
|
private Forest forest;
|
||||||
|
private Hunter hunter;
|
||||||
|
|
||||||
|
public Canvas( Forest forest, Hunter hunter) {
|
||||||
|
this.hunter = hunter;
|
||||||
|
this.forest = forest;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void paintComponent(Graphics graphics) {
|
||||||
|
super.paintComponent(graphics);
|
||||||
|
|
||||||
|
graphics.setColor(Color.RED);
|
||||||
|
graphics.fillOval((int) hunter.getLocation().getX() * RATE, (int) hunter.getLocation().getY() * RATE, 3 * ITEM_RATIO, 3 * ITEM_RATIO);
|
||||||
|
|
||||||
|
graphics.setColor(Color.GREEN);
|
||||||
|
for( Tree tree : forest.getTrees() ) {
|
||||||
|
graphics.fillOval((int) tree.getLocation().getX() * RATE, (int) tree.getLocation().getY() * RATE, 5 * ITEM_RATIO, 5 * ITEM_RATIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
for( Burrow burrow : forest.getBurrows() ) {
|
||||||
|
if( burrow.isFree() ) {
|
||||||
|
graphics.setColor(Color.GRAY);
|
||||||
|
} else {
|
||||||
|
graphics.setColor(Color.DARK_GRAY);
|
||||||
|
}
|
||||||
|
graphics.fillOval((int) burrow.getLocation().getX() * RATE, (int) burrow.getLocation().getY() * RATE, 4 * ITEM_RATIO, 2 * ITEM_RATIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
for( Rabbit rabbit : forest.getRabbits() ) {
|
||||||
|
if( rabbit.getColor() == fr.pavnay.rabbits.model.enums.Color.WHITE ) {
|
||||||
|
graphics.setColor(Color.BLACK);
|
||||||
|
graphics.drawOval((int) rabbit.getLocation().getX() * RATE, (int) rabbit.getLocation().getY() * RATE, 3 * ITEM_RATIO, 3 * ITEM_RATIO);
|
||||||
|
} else {
|
||||||
|
graphics.setColor(rabbit.getColor().getColor());
|
||||||
|
graphics.fillOval((int) rabbit.getLocation().getX() * RATE, (int) rabbit.getLocation().getY() * RATE, 3 * ITEM_RATIO, 3 * ITEM_RATIO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dimension getPreferredSize() {
|
||||||
|
return new Dimension(forest.getEdgeArea() * RATE, forest.getEdgeArea() * RATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
54
src/main/java/fr/pavnay/rabbits/ui/panel/CanvasLegend.java
Normal file
54
src/main/java/fr/pavnay/rabbits/ui/panel/CanvasLegend.java
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
package fr.pavnay.rabbits.ui.panel;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.Graphics;
|
||||||
|
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
|
||||||
|
import fr.pavnay.rabbits.model.Forest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* This class draws the Canvas elements legend
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class CanvasLegend extends JPanel {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1307357862666434838L;
|
||||||
|
|
||||||
|
private int width;
|
||||||
|
|
||||||
|
public CanvasLegend(Forest forest) {
|
||||||
|
this.width = forest.getEdgeArea() * Canvas.RATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void paintComponent(Graphics graphics) {
|
||||||
|
super.paintComponent(graphics);
|
||||||
|
|
||||||
|
graphics.setColor(Color.RED);
|
||||||
|
graphics.fillOval(5, 10, 3 * Canvas.ITEM_RATIO, 3 * Canvas.ITEM_RATIO);
|
||||||
|
graphics.drawString("Hunter", 12, 15);
|
||||||
|
|
||||||
|
graphics.setColor(Color.GREEN);
|
||||||
|
graphics.fillOval(width / 5 + 5, 10, 5 * Canvas.ITEM_RATIO, 5 * Canvas.ITEM_RATIO);
|
||||||
|
graphics.drawString("Trees", width / 5 + 12, 15);
|
||||||
|
|
||||||
|
graphics.setColor(Color.GRAY);
|
||||||
|
graphics.fillOval(2 * width / 5 + 5, 10, 4 * Canvas.ITEM_RATIO, 2 * Canvas.ITEM_RATIO);
|
||||||
|
graphics.drawString("Burrows", 2 * width / 5 + 12, 15);
|
||||||
|
|
||||||
|
graphics.setColor(Color.BLACK);
|
||||||
|
graphics.drawOval(3 * width / 5 + 5, 10, 3 * Canvas.ITEM_RATIO, 3 * Canvas.ITEM_RATIO);
|
||||||
|
graphics.drawString("Rabbits", 3 * width / 5 + 12, 15);
|
||||||
|
|
||||||
|
graphics.setColor(fr.pavnay.rabbits.model.enums.Color.BROWN.getColor());
|
||||||
|
graphics.fillOval(4 * width / 5 + 5, 10, 3 * Canvas.ITEM_RATIO, 3 * Canvas.ITEM_RATIO);
|
||||||
|
graphics.drawString("Rabbits", 4 * width / 5 + 12, 15);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dimension getPreferredSize() {
|
||||||
|
return new Dimension(width, 20);
|
||||||
|
}
|
||||||
|
}
|
||||||
98
src/main/java/fr/pavnay/rabbits/ui/panel/CharacterPanel.java
Normal file
98
src/main/java/fr/pavnay/rabbits/ui/panel/CharacterPanel.java
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
package fr.pavnay.rabbits.ui.panel;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.Font;
|
||||||
|
import java.awt.GridBagLayout;
|
||||||
|
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
|
||||||
|
import fr.pavnay.rabbits.model.Forest;
|
||||||
|
import fr.pavnay.rabbits.model.Hunter;
|
||||||
|
import fr.pavnay.rabbits.ui.UiUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* This class gives some hunt statistics
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class CharacterPanel extends JPanel {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -7823773213443395686L;
|
||||||
|
|
||||||
|
private Hunter hunter;
|
||||||
|
private Forest forest;
|
||||||
|
|
||||||
|
private JLabel ammosCountLabel;
|
||||||
|
private JLabel hungryLevelLabel;
|
||||||
|
private JLabel distanceLabel;
|
||||||
|
|
||||||
|
private JLabel runningRabbitsLabel;
|
||||||
|
private JLabel savedRabbitsLabel;
|
||||||
|
private JLabel deadRabbitsLabel;
|
||||||
|
|
||||||
|
public CharacterPanel(Hunter hunter, Forest forest) {
|
||||||
|
|
||||||
|
this.hunter = hunter;
|
||||||
|
this.forest = forest;
|
||||||
|
|
||||||
|
JPanel innerPanel = new JPanel(new GridBagLayout());
|
||||||
|
|
||||||
|
UiUtils.add(innerPanel, new JLabel("Hunter"), 0, 0, 3, 1);
|
||||||
|
JPanel tmpPanel = new JPanel(new GridBagLayout());
|
||||||
|
UiUtils.add(tmpPanel,new JLabel("Ammos"), 0, 0, 1, 1);
|
||||||
|
ammosCountLabel = new JLabel(String.valueOf(hunter.getAmmos()));
|
||||||
|
Font plainFont = ammosCountLabel.getFont().deriveFont(Font.PLAIN);
|
||||||
|
ammosCountLabel.setFont(plainFont);
|
||||||
|
UiUtils.add(tmpPanel, ammosCountLabel, 1, 0, 1, 1);
|
||||||
|
|
||||||
|
UiUtils.add(tmpPanel, new JLabel("Hungry"), 2, 0, 1, 1);
|
||||||
|
hungryLevelLabel = new JLabel(String.valueOf(hunter.getHungryLevel()));
|
||||||
|
hungryLevelLabel.setFont(plainFont);
|
||||||
|
UiUtils.add(tmpPanel, hungryLevelLabel, 3, 0, 1, 1);
|
||||||
|
|
||||||
|
UiUtils.add(tmpPanel, new JLabel("Distance"), 4, 0, 1, 1);
|
||||||
|
distanceLabel = new JLabel(String.valueOf(hunter.getDistance()));
|
||||||
|
distanceLabel.setFont(plainFont);
|
||||||
|
UiUtils.add(tmpPanel, distanceLabel, 5, 0, 1, 1);
|
||||||
|
|
||||||
|
UiUtils.add(innerPanel, tmpPanel, 0, 1, 1, 1);
|
||||||
|
|
||||||
|
UiUtils.add(innerPanel, new JLabel("Rabbits"), 0, 2, 3, 1);
|
||||||
|
tmpPanel = new JPanel(new GridBagLayout());
|
||||||
|
UiUtils.add(tmpPanel,new JLabel("Running"), 0, 0, 1, 1);
|
||||||
|
runningRabbitsLabel = new JLabel(String.valueOf(forest.getRabbits().size()));
|
||||||
|
plainFont = runningRabbitsLabel.getFont().deriveFont(Font.PLAIN);
|
||||||
|
runningRabbitsLabel.setFont(plainFont);
|
||||||
|
runningRabbitsLabel.setForeground(Color.BLACK);
|
||||||
|
UiUtils.add(tmpPanel, runningRabbitsLabel, 1, 0, 1, 1);
|
||||||
|
|
||||||
|
UiUtils.add(tmpPanel, new JLabel("Saved"), 2, 0, 1, 1);
|
||||||
|
savedRabbitsLabel = new JLabel(String.valueOf(forest.getSavedRabbits().size()));
|
||||||
|
savedRabbitsLabel.setFont(plainFont);
|
||||||
|
savedRabbitsLabel.setForeground(Color.GREEN);
|
||||||
|
UiUtils.add(tmpPanel, savedRabbitsLabel, 3, 0, 1, 1);
|
||||||
|
|
||||||
|
UiUtils.add(tmpPanel, new JLabel("Dead"), 4, 0, 1, 1);
|
||||||
|
deadRabbitsLabel = new JLabel(String.valueOf(forest.getDeadRabbits().size()));
|
||||||
|
deadRabbitsLabel.setFont(plainFont);
|
||||||
|
deadRabbitsLabel.setForeground(Color.RED);
|
||||||
|
UiUtils.add(tmpPanel, deadRabbitsLabel, 5, 0, 1, 1);
|
||||||
|
|
||||||
|
UiUtils.add(innerPanel, tmpPanel, 0, 3, 1, 1);
|
||||||
|
|
||||||
|
add(innerPanel);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void refresh() {
|
||||||
|
ammosCountLabel.setText(String.valueOf(hunter.getAmmos()));
|
||||||
|
hungryLevelLabel.setText(String.valueOf(hunter.getHungryLevel()));
|
||||||
|
distanceLabel.setText(String.valueOf(hunter.getDistance()));
|
||||||
|
|
||||||
|
runningRabbitsLabel.setText(String.valueOf(forest.getRabbits().size()));
|
||||||
|
savedRabbitsLabel.setText(String.valueOf(forest.getSavedRabbits().size()));
|
||||||
|
deadRabbitsLabel.setText(String.valueOf(forest.getDeadRabbits().size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
28
src/main/java/fr/pavnay/rabbits/ui/panel/LogPanel.java
Normal file
28
src/main/java/fr/pavnay/rabbits/ui/panel/LogPanel.java
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package fr.pavnay.rabbits.ui.panel;
|
||||||
|
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.Font;
|
||||||
|
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* This class provides some hunt events
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class LogPanel extends JPanel {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 3786097551382633033L;
|
||||||
|
|
||||||
|
public void addLog(String log) {
|
||||||
|
JLabel label = new JLabel(log);
|
||||||
|
label.setFont(label.getFont().deriveFont(Font.PLAIN));
|
||||||
|
add(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dimension getPreferredSize() {
|
||||||
|
return new Dimension(200, 400);
|
||||||
|
}
|
||||||
|
}
|
||||||
8
src/main/resources/log4j.properties
Normal file
8
src/main/resources/log4j.properties
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
log4j.rootLogger=INFO, CONSOLE
|
||||||
|
|
||||||
|
# CONSOLE is set to be a ConsoleAppender using a PatternLayout
|
||||||
|
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
|
||||||
|
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
|
||||||
|
log4j.appender.CONSOLE.layout.ConversionPattern=%d [%-5p] %c - %m%n
|
||||||
|
|
||||||
|
log4j.logger.fr.pavnay.rabbits=INFO
|
||||||
248
src/test/java/fr/pavnay/rabbits/engine/HuntEngineTest.java
Normal file
248
src/test/java/fr/pavnay/rabbits/engine/HuntEngineTest.java
Normal file
@@ -0,0 +1,248 @@
|
|||||||
|
package fr.pavnay.rabbits.engine;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import java.awt.Point;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import fr.pavnay.rabbits.model.Burrow;
|
||||||
|
import fr.pavnay.rabbits.model.Forest;
|
||||||
|
import fr.pavnay.rabbits.model.Hunter;
|
||||||
|
import fr.pavnay.rabbits.model.Rabbit;
|
||||||
|
import fr.pavnay.rabbits.model.enums.Speed;
|
||||||
|
import fr.pavnay.rabbits.model.enums.Status;
|
||||||
|
|
||||||
|
public class HuntEngineTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateStatusRunning() {
|
||||||
|
Hunter hunter = new Hunter(new Point(3, 2), 10);
|
||||||
|
Forest forest = new Forest(10, 1, 2, 1);
|
||||||
|
HuntEngine engine = new HuntEngine(forest, hunter);
|
||||||
|
engine.updateStatus();
|
||||||
|
|
||||||
|
assertEquals( "Default status is RUNNING", Status.RUNNING, engine.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateStatusRabbitsWin() {
|
||||||
|
Hunter hunter = new Hunter(new Point(3, 2), 10);
|
||||||
|
Forest forest = new Forest(10, 1, 2, 1);
|
||||||
|
HuntEngine engine = new HuntEngine(forest, hunter);
|
||||||
|
hunter.setAmmos(0);
|
||||||
|
engine.updateStatus();
|
||||||
|
|
||||||
|
assertEquals( "Default status is RUNNING", Status.RABBITS_WIN, engine.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateStatusHunterWins() {
|
||||||
|
Hunter hunter = new Hunter(new Point(3, 2), 10);
|
||||||
|
Forest forest = new Forest(10, 1, 2, 1);
|
||||||
|
HuntEngine engine = new HuntEngine(forest, hunter);
|
||||||
|
forest.getDeadRabbits().addAll(forest.getRabbits());
|
||||||
|
forest.getRabbits().clear();
|
||||||
|
engine.updateStatus();
|
||||||
|
|
||||||
|
assertEquals( "Default status is RUNNING", Status.HUNTER_WINS, engine.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateStatusHunterLoose() {
|
||||||
|
Hunter hunter = new Hunter(new Point(3, 2), 10);
|
||||||
|
Forest forest = new Forest(10, 1, 2, 2);
|
||||||
|
HuntEngine engine = new HuntEngine(forest, hunter);
|
||||||
|
forest.getDeadRabbits().add(forest.getRabbits().get(0));
|
||||||
|
forest.getSavedRabbits().add(forest.getRabbits().get(1));
|
||||||
|
forest.getRabbits().clear();
|
||||||
|
engine.updateStatus();
|
||||||
|
|
||||||
|
assertEquals( "Default status is RUNNING", Status.RABBITS_WIN, engine.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMoveHunterCloseToDestination() {
|
||||||
|
Hunter hunter = new Hunter(new Point(0, 0), 10);
|
||||||
|
hunter.setDestination(new Point(2, 0));
|
||||||
|
Forest forest = new Forest(10, 1, 2, 1);
|
||||||
|
HuntEngine engine = new HuntEngine(forest, hunter);
|
||||||
|
|
||||||
|
engine.move(hunter);
|
||||||
|
assertNotEquals("Destination has changed - X", 2, hunter.getDestination().getX());
|
||||||
|
assertNotEquals("Destination has changed - Y", 0, hunter.getDestination().getY());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMoveHunterFarFromDestination() {
|
||||||
|
Hunter hunter = new Hunter(new Point(0, 0), 10);
|
||||||
|
hunter.setDestination(new Point(20, 0));
|
||||||
|
Forest forest = new Forest(10, 1, 2, 1);
|
||||||
|
HuntEngine engine = new HuntEngine(forest, hunter);
|
||||||
|
|
||||||
|
engine.move(hunter);
|
||||||
|
assertNotEquals("Destination has changed - X", 20, hunter.getDestination().getX());
|
||||||
|
assertNotEquals("Destination has changed - Y", 0, hunter.getDestination().getY());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMoveRabbitCloseToFreeBurrow() {
|
||||||
|
Hunter hunter = new Hunter(new Point(0, 0), 10);
|
||||||
|
Forest forest = new Forest(10, 1, 2, 1);
|
||||||
|
HuntEngine engine = new HuntEngine(forest, hunter);
|
||||||
|
|
||||||
|
Burrow burrow = forest.getBurrows().get(0);
|
||||||
|
burrow.getLocation().setLocation(2, 0);
|
||||||
|
|
||||||
|
Rabbit rabbit = forest.getRabbits().get(0);
|
||||||
|
rabbit.getLocation().setLocation(new Point(0, 0));
|
||||||
|
rabbit.setSpeed(Speed.MEDIUM.getSpeed());
|
||||||
|
rabbit.setRefuge(burrow);
|
||||||
|
|
||||||
|
engine.move(rabbit);
|
||||||
|
assertFalse("Lucky rabbit doesn't run anymore", forest.getRabbits().contains(rabbit));
|
||||||
|
assertNull("No more destination", rabbit.getDestination());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMoveRabbitCloseToNotFreeBurrow() {
|
||||||
|
Hunter hunter = new Hunter(new Point(0, 0), 10);
|
||||||
|
Forest forest = new Forest(10, 1, 2, 1);
|
||||||
|
HuntEngine engine = new HuntEngine(forest, hunter);
|
||||||
|
|
||||||
|
Burrow burrow = forest.getBurrows().get(0);
|
||||||
|
burrow.getLocation().setLocation(2, 0);
|
||||||
|
burrow.setFree(false);
|
||||||
|
|
||||||
|
Rabbit rabbit = forest.getRabbits().get(0);
|
||||||
|
rabbit.getLocation().setLocation(new Point(0, 0));
|
||||||
|
rabbit.setSpeed(Speed.MEDIUM.getSpeed());
|
||||||
|
rabbit.setRefuge(burrow);
|
||||||
|
|
||||||
|
engine.move(rabbit);
|
||||||
|
assertTrue("Rabbit still running", forest.getRabbits().contains(rabbit));
|
||||||
|
assertEquals("New destination : next burrow",forest.getBurrows().get(1).getLocation(), rabbit.getDestination());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMoveRabbitToFarFromBurrow() {
|
||||||
|
Hunter hunter = new Hunter(new Point(0, 0), 10);
|
||||||
|
Forest forest = new Forest(10, 1, 2, 1);
|
||||||
|
HuntEngine engine = new HuntEngine(forest, hunter);
|
||||||
|
|
||||||
|
Burrow burrow = forest.getBurrows().get(0);
|
||||||
|
burrow.getLocation().setLocation(20, 0);
|
||||||
|
|
||||||
|
Rabbit rabbit = forest.getRabbits().get(0);
|
||||||
|
rabbit.getLocation().setLocation(new Point(0, 0));
|
||||||
|
rabbit.setSpeed(Speed.MEDIUM.getSpeed());
|
||||||
|
rabbit.setRefuge(burrow);
|
||||||
|
|
||||||
|
engine.move(rabbit);
|
||||||
|
assertTrue("Rabbit still running", forest.getRabbits().contains(rabbit));
|
||||||
|
assertEquals("Burrow still the destination", burrow.getLocation(), rabbit.getDestination());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMoveRabbitCloseToDestination() {
|
||||||
|
Hunter hunter = new Hunter(new Point(0, 0), 10);
|
||||||
|
Forest forest = new Forest(10, 1, 2, 1);
|
||||||
|
HuntEngine engine = new HuntEngine(forest, hunter);
|
||||||
|
|
||||||
|
Rabbit rabbit = forest.getRabbits().get(0);
|
||||||
|
rabbit.getLocation().setLocation(new Point(0, 0));
|
||||||
|
rabbit.setSpeed(Speed.MEDIUM.getSpeed());
|
||||||
|
rabbit.setDestination(new Point(3, 0));
|
||||||
|
engine.move(rabbit);
|
||||||
|
assertNotEquals("New destination", new Point(3, 0), rabbit.getDestination());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMoveRabbitFarFromDestination() {
|
||||||
|
Hunter hunter = new Hunter(new Point(0, 0), 10);
|
||||||
|
Forest forest = new Forest(10, 1, 2, 1);
|
||||||
|
HuntEngine engine = new HuntEngine(forest, hunter);
|
||||||
|
|
||||||
|
Rabbit rabbit = forest.getRabbits().get(0);
|
||||||
|
rabbit.getLocation().setLocation(new Point(0, 0));
|
||||||
|
rabbit.setSpeed(Speed.MEDIUM.getSpeed());
|
||||||
|
rabbit.setDestination(new Point(13, 0));
|
||||||
|
|
||||||
|
engine.move(rabbit);
|
||||||
|
assertEquals("Same destination", new Point(13, 0), rabbit.getDestination());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetRandomDestinationHunter() {
|
||||||
|
Hunter hunter = new Hunter(new Point(0, 0), 10);
|
||||||
|
hunter.setDestination(null);
|
||||||
|
Forest forest = new Forest(10, 1, 2, 1);
|
||||||
|
HuntEngine engine = new HuntEngine(forest, hunter);
|
||||||
|
|
||||||
|
engine.setRandomDestination(hunter);
|
||||||
|
assertNotNull("Destination set", hunter.getDestination());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetRandomDestinationRabbit() {
|
||||||
|
Hunter hunter = new Hunter(new Point(0, 0), 10);
|
||||||
|
Forest forest = new Forest(10, 1, 2, 1);
|
||||||
|
HuntEngine engine = new HuntEngine(forest, hunter);
|
||||||
|
Rabbit rabbit = forest.getRabbits().get(0);
|
||||||
|
rabbit.setDestination(null);
|
||||||
|
engine.setRandomDestination(rabbit);
|
||||||
|
assertNotNull("Destination set", rabbit.getDestination());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGoHunter() {
|
||||||
|
Hunter hunter = new Hunter(new Point(0, 0), 10);
|
||||||
|
hunter.setDestination(new Point(20, 20));
|
||||||
|
Forest forest = new Forest(10, 1, 2, 1);
|
||||||
|
HuntEngine engine = new HuntEngine(forest, hunter);
|
||||||
|
|
||||||
|
engine.go(hunter);
|
||||||
|
|
||||||
|
assertEquals("Location has changed", new Point(3, 3), hunter.getLocation());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGoRabbit() {
|
||||||
|
Hunter hunter = new Hunter(new Point(0, 0), 10);
|
||||||
|
Forest forest = new Forest(10, 1, 2, 1);
|
||||||
|
HuntEngine engine = new HuntEngine(forest, hunter);
|
||||||
|
|
||||||
|
Rabbit rabbit = forest.getRabbits().get(0);
|
||||||
|
rabbit.getLocation().setLocation(new Point(0, 0));
|
||||||
|
rabbit.setSpeed(Speed.MEDIUM.getSpeed());
|
||||||
|
rabbit.setDestination(new Point(13, 13));
|
||||||
|
|
||||||
|
engine.go(rabbit);
|
||||||
|
|
||||||
|
assertEquals("Location has changed", new Point(3, 3), rabbit.getLocation());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSavedRabbit() {
|
||||||
|
Hunter hunter = new Hunter(new Point(0, 0), 10);
|
||||||
|
Forest forest = new Forest(10, 1, 2, 1);
|
||||||
|
HuntEngine engine = new HuntEngine(forest, hunter);
|
||||||
|
|
||||||
|
Burrow burrow = forest.getBurrows().get(0);
|
||||||
|
burrow.getLocation().setLocation(2, 0);
|
||||||
|
|
||||||
|
Rabbit rabbit = forest.getRabbits().get(0);
|
||||||
|
rabbit.getLocation().setLocation(new Point(0, 0));
|
||||||
|
rabbit.setSpeed(Speed.MEDIUM.getSpeed());
|
||||||
|
rabbit.setRefuge(burrow);
|
||||||
|
|
||||||
|
engine.go(rabbit);
|
||||||
|
|
||||||
|
assertEquals("Destination has not changed", new Point(5, 0), rabbit.getLocation());
|
||||||
|
}
|
||||||
|
}
|
||||||
246
src/test/java/fr/pavnay/rabbits/model/ForestTest.java
Normal file
246
src/test/java/fr/pavnay/rabbits/model/ForestTest.java
Normal file
@@ -0,0 +1,246 @@
|
|||||||
|
package fr.pavnay.rabbits.model;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import java.awt.Point;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.matchers.JUnitMatchers;
|
||||||
|
import org.junit.rules.ExpectedException;
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
public class ForestTest {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public ExpectedException thrown = ExpectedException.none();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInitSuccess() {
|
||||||
|
Forest forest = new Forest(10, 1, 1, 1);
|
||||||
|
assertNotNull("Forest created", forest);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInitFailureAreaMin() {
|
||||||
|
thrown.expect(IllegalArgumentException.class);
|
||||||
|
thrown.expectMessage(JUnitMatchers.containsString("Area"));
|
||||||
|
|
||||||
|
new Forest(0, 1, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInitFailureAreaMax() {
|
||||||
|
thrown.expect(IllegalArgumentException.class);
|
||||||
|
thrown.expectMessage(JUnitMatchers.containsString("Area"));
|
||||||
|
|
||||||
|
new Forest(11, 1, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInitFailureTreesMin() {
|
||||||
|
thrown.expect(IllegalArgumentException.class);
|
||||||
|
thrown.expectMessage(JUnitMatchers.containsString("Tree"));
|
||||||
|
|
||||||
|
new Forest(1, 0, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInitFailureTreesMax() {
|
||||||
|
thrown.expect(IllegalArgumentException.class);
|
||||||
|
thrown.expectMessage(JUnitMatchers.containsString("Tree"));
|
||||||
|
|
||||||
|
new Forest(10, 1001, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInitFailureNoRabbits() {
|
||||||
|
thrown.expect(IllegalArgumentException.class);
|
||||||
|
thrown.expectMessage(JUnitMatchers.containsString("rabbits"));
|
||||||
|
|
||||||
|
new Forest(10, 100, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInitFailureNotEnoughBurrows() {
|
||||||
|
thrown.expect(IllegalArgumentException.class);
|
||||||
|
thrown.expectMessage(JUnitMatchers.containsString("burrow"));
|
||||||
|
|
||||||
|
new Forest(10, 100, 1, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsBetweenSuccess() {
|
||||||
|
Hunter hunter = new Hunter(new Point(0,0), 10);
|
||||||
|
Forest forest = new Forest(10, 1, 1, 1);
|
||||||
|
Rabbit rabbit = new Rabbit(new Point(4, 4));
|
||||||
|
Tree tree = new Tree(new Point(2, 2));
|
||||||
|
assertTrue("Tree is between hunter and rabbit", forest.isBetween(hunter.getLocation(), rabbit.getLocation(), tree.getLocation()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCanViewSuccess() {
|
||||||
|
Hunter hunter = new Hunter(new Point(0,0), 10);
|
||||||
|
Forest forest = new Forest(10, 2, 1, 1);
|
||||||
|
forest.getTrees().get(0).getLocation().setLocation(10, 0);
|
||||||
|
forest.getTrees().get(1).getLocation().setLocation(20, 0);
|
||||||
|
Rabbit rabbit = new Rabbit(new Point(4, 4));
|
||||||
|
assertTrue("No Tree between hunter and rabbit", forest.canView(hunter, rabbit));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCanViewFailure() {
|
||||||
|
Hunter hunter = new Hunter(new Point(0,0), 10);
|
||||||
|
Forest forest = new Forest(10, 2, 1, 1);
|
||||||
|
forest.getTrees().get(0).getLocation().setLocation(2, 2);
|
||||||
|
forest.getTrees().get(1).getLocation().setLocation(2, 0);
|
||||||
|
Rabbit rabbit = new Rabbit(new Point(4, 4));
|
||||||
|
assertFalse("Tree is between hunter and rabbit", forest.canView(hunter, rabbit));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsBetweenFailureTreeBehind() {
|
||||||
|
Hunter hunter = new Hunter(new Point(0,0), 10);
|
||||||
|
Forest forest = new Forest(10, 1, 1, 1);
|
||||||
|
Rabbit rabbit = new Rabbit(new Point(4, 4));
|
||||||
|
Tree tree = new Tree(new Point(5, 5));
|
||||||
|
assertFalse("Tree is behind the rabbit", forest.isBetween(hunter.getLocation(), rabbit.getLocation(), tree.getLocation()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsBetweenFailureTreeSomewhere() {
|
||||||
|
Hunter hunter = new Hunter(new Point(0,0), 10);
|
||||||
|
Forest forest = new Forest(10, 1, 1, 1);
|
||||||
|
Rabbit rabbit = new Rabbit(new Point(4, 4));
|
||||||
|
Tree tree = new Tree(new Point(10, 5));
|
||||||
|
assertFalse("Tree is not in the hunter-rabbit aligment", forest.isBetween(hunter.getLocation(), rabbit.getLocation(), tree.getLocation()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testKilledRabbitSuccess() {
|
||||||
|
Forest forest = new Forest(10, 1, 2, 2);
|
||||||
|
Rabbit rabbit = forest.getRabbits().get(0);
|
||||||
|
forest.killedRabbit(rabbit);
|
||||||
|
|
||||||
|
assertFalse("Poor killed rabbit still running", forest.getRabbits().contains(rabbit));
|
||||||
|
assertEquals("Still one rabbit alive", 1, forest.getRabbits().size());
|
||||||
|
assertTrue("Poor killed rabbit can't run", forest.getDeadRabbits().contains(rabbit));
|
||||||
|
assertEquals("One dead rabbit", 1, forest.getDeadRabbits().size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSavedRabbitSuccess() {
|
||||||
|
Forest forest = new Forest(10, 1, 1, 1);
|
||||||
|
Rabbit rabbit = forest.getRabbits().get(0);
|
||||||
|
forest.savedRabbit(rabbit);
|
||||||
|
|
||||||
|
assertFalse("Poor saved rabbit still running", forest.getRabbits().contains(rabbit));
|
||||||
|
assertTrue("Lucky rabbit can't run", forest.getSavedRabbits().contains(rabbit));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetRabbitsInRangeSuccess() {
|
||||||
|
Hunter hunter = new Hunter(new Point(0,0), 10);
|
||||||
|
Forest forest = new Forest(10, 1, 2, 2);
|
||||||
|
forest.getRabbits().get(0).getLocation().setLocation(0, 5); // First rabbit in range
|
||||||
|
forest.getRabbits().get(1).getLocation().setLocation(0, 15); // Seconde one out of range
|
||||||
|
|
||||||
|
List<Rabbit> rabbitsInRange = forest.getRabbitsInRange(hunter);
|
||||||
|
assertEquals("One rabbit in range", 1, rabbitsInRange.size());
|
||||||
|
assertTrue("First rabbit in range", rabbitsInRange.contains(forest.getRabbits().get(0)));
|
||||||
|
assertFalse("Second rabbit out of range", rabbitsInRange.contains(forest.getRabbits().get(1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetNearestBurrowFirst() {
|
||||||
|
Hunter hunter = new Hunter(new Point(0, 1), 10);
|
||||||
|
Forest forest = new Forest(10, 1, 2, 1);
|
||||||
|
forest.getBurrows().get(0).getLocation().setLocation(7, 2);
|
||||||
|
forest.getBurrows().get(1).getLocation().setLocation(9, 0);
|
||||||
|
Rabbit rabbit = forest.getRabbits().get(0);
|
||||||
|
rabbit.getLocation().setLocation(4, 1);
|
||||||
|
|
||||||
|
assertEquals("Second burrow is nearest from rabbit", forest.getBurrows().get(0), forest.getNearestBurrow(hunter, rabbit));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetNearestBurrowSecond() {
|
||||||
|
Hunter hunter = new Hunter(new Point(0, 1), 10);
|
||||||
|
Forest forest = new Forest(10, 1, 2, 1);
|
||||||
|
forest.getBurrows().get(0).getLocation().setLocation(9, 0);
|
||||||
|
forest.getBurrows().get(1).getLocation().setLocation(7, 2);
|
||||||
|
Rabbit rabbit = forest.getRabbits().get(0);
|
||||||
|
rabbit.getLocation().setLocation(4, 1);
|
||||||
|
|
||||||
|
assertEquals("Second burrow is nearest from rabbit", forest.getBurrows().get(1), forest.getNearestBurrow(hunter, rabbit));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetNearestBurrowWorstIsBetter() {
|
||||||
|
Hunter hunter = new Hunter(new Point(0, 1), 10);
|
||||||
|
Forest forest = new Forest(10, 1, 2, 1);
|
||||||
|
forest.getBurrows().get(0).getLocation().setLocation(7, 2);
|
||||||
|
forest.getBurrows().get(1).getLocation().setLocation(3, 2);
|
||||||
|
Rabbit rabbit = forest.getRabbits().get(0);
|
||||||
|
rabbit.getLocation().setLocation(4, 1);
|
||||||
|
|
||||||
|
assertEquals("Second burrow is nearest from rabbit", forest.getBurrows().get(1), forest.getNearestBurrow(hunter, rabbit));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetNearestBurrowNotVisited() {
|
||||||
|
Hunter hunter = new Hunter(new Point(0, 1), 10);
|
||||||
|
Forest forest = new Forest(10, 1, 2, 1);
|
||||||
|
forest.getBurrows().get(0).getLocation().setLocation(7, 2);
|
||||||
|
forest.getBurrows().get(1).getLocation().setLocation(9, 0);
|
||||||
|
Rabbit rabbit = forest.getRabbits().get(0);
|
||||||
|
rabbit.getLocation().setLocation(4, 1);
|
||||||
|
rabbit.setRefuge(forest.getBurrows().get(0));
|
||||||
|
|
||||||
|
assertEquals("Second burrow was not visited by the rabbit", forest.getBurrows().get(1), forest.getNearestBurrow(hunter, rabbit));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEscapeScared() {
|
||||||
|
Hunter hunter = new Hunter(new Point(3, 2), 10);
|
||||||
|
Forest forest = new Forest(10, 1, 1, 1);
|
||||||
|
Rabbit rabbit = forest.getRabbits().get(0);
|
||||||
|
rabbit.getLocation().setLocation(6, 3);
|
||||||
|
rabbit.setScared(true);
|
||||||
|
|
||||||
|
forest.escape(hunter, rabbit);
|
||||||
|
Burrow burrow = forest.getBurrows().get(0);
|
||||||
|
assertEquals("Right location X", burrow.getLocation().getX(), rabbit.getDestination().getX(), 0);
|
||||||
|
assertEquals("Right location Y", burrow.getLocation().getY(), rabbit.getDestination().getY(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEscapeNotScared() {
|
||||||
|
Hunter hunter = new Hunter(new Point(3, 2), 10);
|
||||||
|
Forest forest = new Forest(10, 1, 2, 1);
|
||||||
|
Rabbit rabbit = forest.getRabbits().get(0);
|
||||||
|
rabbit.getLocation().setLocation(6, 3);
|
||||||
|
|
||||||
|
forest.escape(hunter, rabbit);
|
||||||
|
|
||||||
|
assertEquals("Right location X", 9, rabbit.getDestination().getX(), 0);
|
||||||
|
assertEquals("Right location Y", 4, rabbit.getDestination().getY(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEscapeNotScaredOutOfForest() {
|
||||||
|
Hunter hunter = new Hunter(new Point(5, 3), 10);
|
||||||
|
Forest forest = new Forest(10, 1, 2, 1);
|
||||||
|
Rabbit rabbit = forest.getRabbits().get(0);
|
||||||
|
rabbit.getLocation().setLocation(2, 2);
|
||||||
|
|
||||||
|
forest.escape(hunter, rabbit);
|
||||||
|
|
||||||
|
assertEquals("Right location X", 0, rabbit.getDestination().getX(), 0);
|
||||||
|
assertEquals("Right location Y", 1, rabbit.getDestination().getY(), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
108
src/test/java/fr/pavnay/rabbits/model/HunterTest.java
Normal file
108
src/test/java/fr/pavnay/rabbits/model/HunterTest.java
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
package fr.pavnay.rabbits.model;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import java.awt.Point;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class HunterTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInRangeSuccess() {
|
||||||
|
Hunter hunter = new Hunter(new Point(0, 0), 10);
|
||||||
|
Rabbit rabbit = new Rabbit(new Point(10, 0));
|
||||||
|
assertTrue("Rabbit is in hunter range", hunter.isInRange(rabbit));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInRangeFailure() {
|
||||||
|
Hunter hunter = new Hunter(new Point(0, 0), 10);
|
||||||
|
Rabbit rabbit = new Rabbit(new Point(11, 0));
|
||||||
|
assertFalse("Rabbit is out of hunter range", hunter.isInRange(rabbit));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testShootSuccess() {
|
||||||
|
Hunter hunter = new Hunter(new Point(0, 0), 10);
|
||||||
|
Rabbit rabbit = new Rabbit(new Point(0, 0));
|
||||||
|
assertTrue("Rabbit is close to the hunter. Shot successfully", hunter.shoot(rabbit));
|
||||||
|
assertEquals("Hunter's ammos decreases", 9, hunter.getAmmos());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testShootNoMoreAmmosFailure() {
|
||||||
|
Hunter hunter = new Hunter(new Point(0, 0), 10);
|
||||||
|
Rabbit rabbit = new Rabbit(new Point(0, 0));
|
||||||
|
hunter.shoot(rabbit);
|
||||||
|
hunter.shoot(rabbit);
|
||||||
|
hunter.shoot(rabbit);
|
||||||
|
hunter.shoot(rabbit);
|
||||||
|
hunter.shoot(rabbit);
|
||||||
|
hunter.shoot(rabbit);
|
||||||
|
hunter.shoot(rabbit);
|
||||||
|
hunter.shoot(rabbit);
|
||||||
|
hunter.shoot(rabbit);
|
||||||
|
hunter.shoot(rabbit);
|
||||||
|
assertFalse("No more ammos. Shot failure", hunter.shoot(rabbit));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testShootFailure() {
|
||||||
|
Hunter hunter = new Hunter(new Point(0, 0), 10);
|
||||||
|
Rabbit rabbit = new Rabbit(new Point(10, 0));
|
||||||
|
assertFalse("Rabbit is out of hunter's range. Shot failure", hunter.shoot(rabbit));
|
||||||
|
assertEquals("Hunter's ammos decreases", 9, hunter.getAmmos());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAccuracyRate() {
|
||||||
|
Hunter hunter = new Hunter(new Point(0, 0), 10);
|
||||||
|
Rabbit rabbit = new Rabbit(new Point(5, 0));
|
||||||
|
assertEquals("Hunter's half rate to shot", hunter.getAccuracyRate(rabbit), 0.5, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAccuracyRateHalfAmmo() {
|
||||||
|
Hunter hunter = new Hunter(new Point(0, 0), 10);
|
||||||
|
Rabbit rabbit = new Rabbit(new Point(5, 0));
|
||||||
|
hunter.setAmmos(5);
|
||||||
|
assertEquals("Hunter's half rate to shot", hunter.getAccuracyRate(rabbit), 0.475, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAccuracyRateHalfHungryLevel() {
|
||||||
|
Hunter hunter = new Hunter(new Point(0, 0), 10);
|
||||||
|
Rabbit rabbit = new Rabbit(new Point(5, 0));
|
||||||
|
hunter.setHungryLevel(5);
|
||||||
|
assertEquals("Hunter's half hungry level", hunter.getAccuracyRate(rabbit), 0.45, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAccuracyRateFullHungryLevel() {
|
||||||
|
Hunter hunter = new Hunter(new Point(0, 0), 10);
|
||||||
|
Rabbit rabbit = new Rabbit(new Point(5, 0));
|
||||||
|
hunter.setHungryLevel(10);
|
||||||
|
assertEquals("Hunter's half hungry level", hunter.getAccuracyRate(rabbit), 0.4, 0.001);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAccuracyRateHalfAmmosHalfHungryLevel() {
|
||||||
|
Hunter hunter = new Hunter(new Point(0, 0), 10);
|
||||||
|
Rabbit rabbit = new Rabbit(new Point(5, 0));
|
||||||
|
hunter.setAmmos(5);
|
||||||
|
hunter.setHungryLevel(5);
|
||||||
|
assertEquals("Hunter's half hungry level", hunter.getAccuracyRate(rabbit), 0.425, 0.001);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAccuracyRateHalfAmmosFullHungryLevel() {
|
||||||
|
Hunter hunter = new Hunter(new Point(0, 0), 10);
|
||||||
|
Rabbit rabbit = new Rabbit(new Point(5, 0));
|
||||||
|
hunter.setAmmos(5);
|
||||||
|
hunter.setHungryLevel(10);
|
||||||
|
assertEquals("Hunter's half hungry level", hunter.getAccuracyRate(rabbit), 0.375, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
29
src/test/java/fr/pavnay/rabbits/model/RabbitTest.java
Normal file
29
src/test/java/fr/pavnay/rabbits/model/RabbitTest.java
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package fr.pavnay.rabbits.model;
|
||||||
|
|
||||||
|
import java.awt.Point;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import fr.pavnay.rabbits.model.enums.Speed;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
public class RabbitTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSlowDown() {
|
||||||
|
Rabbit rabbit = new Rabbit(new Point(0,0));
|
||||||
|
rabbit.setSpeed(Speed.MEDIUM.getSpeed());
|
||||||
|
rabbit.slowDown();
|
||||||
|
assertEquals("Rabbit slow down", Speed.MEDIUM.getSpeed() - 1, rabbit.getSpeed());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSlowDownStopped() {
|
||||||
|
Rabbit rabbit = new Rabbit(new Point(0,0));
|
||||||
|
rabbit.setSpeed(Speed.SLOW.getSpeed());
|
||||||
|
rabbit.slowDown();
|
||||||
|
rabbit.slowDown();
|
||||||
|
assertEquals("Rabbit stopped", Speed.STOPPED.getSpeed(), rabbit.getSpeed());
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user