128 lines
5.5 KiB
Java
128 lines
5.5 KiB
Java
|
package comp1110.ass2;
|
||
|
|
||
|
import comp1110.ass2.testdata.GameDataLoader;
|
||
|
import org.junit.jupiter.api.Assertions;
|
||
|
import org.junit.jupiter.api.Test;
|
||
|
import org.junit.jupiter.api.Timeout;
|
||
|
|
||
|
import java.util.HashMap;
|
||
|
import java.util.HashSet;
|
||
|
import java.util.List;
|
||
|
import java.util.Set;
|
||
|
import java.util.concurrent.TimeUnit;
|
||
|
|
||
|
@Timeout(value = 10000, unit = TimeUnit.MILLISECONDS)
|
||
|
public class DistributeResourcesTest {
|
||
|
|
||
|
private static final Set<Character> resourceCharacters = new HashSet<>(List.of('C','B','W','P','S'));
|
||
|
private static final int SIMULATIONS = 5000;
|
||
|
private static final int BOUNDARY = 150;
|
||
|
private static final double RESOURCE_EXPECTED = ((double) SIMULATIONS) * 6 / 32;
|
||
|
private static final double STATUETTE_EXPECTED = ((double) SIMULATIONS) * 8 / 32;
|
||
|
|
||
|
private static String fetchResourceComponent(String stateString){
|
||
|
String[] parts = stateString.split("; ");
|
||
|
for (String part : parts) {
|
||
|
Assertions.assertFalse(part.isEmpty(),
|
||
|
"Empty statement in state string: " + stateString);
|
||
|
if (part.charAt(0) == 'r'){
|
||
|
Assertions.assertTrue(part.length() >= 3,
|
||
|
"Unclaimed resource statement too short in state string: " + stateString);
|
||
|
return part.substring(2);
|
||
|
}
|
||
|
}
|
||
|
throw new IllegalArgumentException("No resource statement found in: " + stateString);
|
||
|
}
|
||
|
|
||
|
private static String fetchStoneCircleComponent(String stateString){
|
||
|
String[] parts = stateString.split("; ");
|
||
|
for (String part : parts) {
|
||
|
if (part.charAt(0) == 's'){
|
||
|
return part.substring(2);
|
||
|
}
|
||
|
}
|
||
|
throw new IllegalArgumentException("No resource component found for: " + stateString);
|
||
|
}
|
||
|
|
||
|
|
||
|
private static HashMap<String, HashMap<Character, Integer>> simulateDistribution(String toDistribute){
|
||
|
HashMap<String, HashMap<Character, Integer>> overallDistribution = new HashMap<>();
|
||
|
|
||
|
for(String stoneCircle : fetchStoneCircleComponent(toDistribute).split(" ")){
|
||
|
HashMap<Character, Integer> resourceHashmap = new HashMap<>();
|
||
|
for(Character r : resourceCharacters){
|
||
|
resourceHashmap.put(r, 0);
|
||
|
}
|
||
|
overallDistribution.put(stoneCircle, resourceHashmap);
|
||
|
}
|
||
|
|
||
|
for (int i = 0; i < SIMULATIONS; i++) {
|
||
|
String resourceComponent = fetchResourceComponent(BlueLagoon.distributeResources(toDistribute));
|
||
|
Character lastCharacter = null;
|
||
|
|
||
|
HashMap<Character, Integer> resourceCounts = new HashMap<>();
|
||
|
for(Character r : resourceCharacters){
|
||
|
resourceCounts.put(r, 0);
|
||
|
}
|
||
|
for(String value : resourceComponent.split(" ")){
|
||
|
if(value.length() == 1 && resourceCharacters.contains(value.charAt(0))){
|
||
|
lastCharacter = value.charAt(0);
|
||
|
continue;
|
||
|
}
|
||
|
resourceCounts.put(lastCharacter, resourceCounts.get(lastCharacter) + 1);
|
||
|
overallDistribution.get(value).put(lastCharacter, overallDistribution.get(value).get(lastCharacter) + 1);
|
||
|
}
|
||
|
|
||
|
for(Character r : resourceCharacters){
|
||
|
Assertions.assertEquals(r == 'S' ? 8 : 6, resourceCounts.get(r), "Expected " + (r == 'S' ? 8 : 6)
|
||
|
+ " resources of type " + r + " to be distributed amongst the below board but got "
|
||
|
+ resourceCounts.get(r) + " instead\n" + toDistribute);
|
||
|
}
|
||
|
}
|
||
|
return overallDistribution;
|
||
|
}
|
||
|
|
||
|
|
||
|
private static void testSufficientlyRandom(HashMap<String, HashMap<Character, Integer>> distribution){
|
||
|
for (String coordinate : distribution.keySet()){
|
||
|
int total = 0;
|
||
|
for(Character resource : resourceCharacters){
|
||
|
int amount = distribution.get(coordinate).get(resource);
|
||
|
if(resource.equals('S')){
|
||
|
Assertions.assertTrue(STATUETTE_EXPECTED - BOUNDARY <= amount && amount <= STATUETTE_EXPECTED + BOUNDARY,
|
||
|
"After " + SIMULATIONS + " simulations expect statuettes at coordinate " + coordinate
|
||
|
+ " to be between " + (STATUETTE_EXPECTED - BOUNDARY) + " and " + (STATUETTE_EXPECTED + BOUNDARY)
|
||
|
+ " but got " + amount + " instead");
|
||
|
} else{
|
||
|
Assertions.assertTrue(RESOURCE_EXPECTED - BOUNDARY <= amount && amount <= RESOURCE_EXPECTED + BOUNDARY,
|
||
|
"After " + SIMULATIONS + " simulations expect resource " + resource + " at coordinate " + coordinate
|
||
|
+ " to be between " + (RESOURCE_EXPECTED - BOUNDARY) + " and " + (RESOURCE_EXPECTED + BOUNDARY)
|
||
|
+ " but got " + amount + " instead");
|
||
|
}
|
||
|
total += amount;
|
||
|
}
|
||
|
Assertions.assertEquals(SIMULATIONS, total, " expected " + SIMULATIONS + " total resources counted at coordinate "
|
||
|
+ coordinate + " after " + SIMULATIONS + " simulations but counted " + total);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static void testGame(String game){
|
||
|
testSufficientlyRandom(simulateDistribution(game));
|
||
|
}
|
||
|
|
||
|
@Test
|
||
|
public void testDefaultGame(){
|
||
|
testGame(GameDataLoader.DEFAULT_GAME);
|
||
|
}
|
||
|
|
||
|
@Test
|
||
|
public void testWheelsGame(){
|
||
|
testGame(GameDataLoader.WHEELS_GAME);
|
||
|
}
|
||
|
|
||
|
@Test
|
||
|
public void testFaceGame(){
|
||
|
testGame(GameDataLoader.FACE_GAME);
|
||
|
}
|
||
|
}
|