package greymerk.roguelike.dungeon.base;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import greymerk.roguelike.util.WeightedChoice;
import greymerk.roguelike.util.WeightedRandomizer;
public class DungeonFactory implements IDungeonFactory {
private Map<DungeonRoom, Integer> singles;
private Map<DungeonRoom, Integer> multiple;
private DungeonRoom base;
public DungeonFactory(){
this(DungeonRoom.CORNER);
}
public DungeonFactory(DungeonRoom base){
singles = new HashMap<DungeonRoom, Integer>();
multiple = new HashMap<DungeonRoom, Integer>();
this.base = base;
}
public DungeonFactory(JsonArray json) throws Exception {
this();
for(JsonElement e : json){
JsonObject entry = e.getAsJsonObject();
String mode = (entry.get("mode").getAsString()).toLowerCase();
String type = (entry.get("type").getAsString()).toUpperCase();
int weight = entry.has("weight") ? entry.get("weight").getAsInt() : 1;
if(!DungeonRoom.contains(type)){
throw new Exception("No such dungeon: " + type);
}
DungeonRoom toAdd = DungeonRoom.valueOf(entry.get("type").getAsString());
if(mode.equals("single")){
this.addSingle(toAdd);
}
if(mode.equals("random")){
this.addRandom(toAdd, weight);
}
}
}
public DungeonFactory(DungeonFactory toCopy){
this();
for(DungeonRoom room : toCopy.singles.keySet()){
this.singles.put(room, toCopy.singles.get(room));
}
for(DungeonRoom room : toCopy.multiple.keySet()){
this.multiple.put(room, toCopy.multiple.get(room));
}
base = toCopy.base;
}
public DungeonFactory(DungeonFactory base, DungeonFactory other){
this();
this.base = other.base;
for(DungeonRoom room : base.singles.keySet()){
this.singles.put(room, base.singles.get(room));
}
for(DungeonRoom room : base.multiple.keySet()){
this.multiple.put(room, base.multiple.get(room));
}
for(DungeonRoom room : other.singles.keySet()){
this.singles.put(room, other.singles.get(room));
}
for(DungeonRoom room : other.multiple.keySet()){
this.multiple.put(room, other.multiple.get(room));
}
}
public void addSingle(DungeonRoom type){
this.addSingle(type, 1);
}
public void addSingle(DungeonRoom type, int num){
if(!singles.containsKey(type)){
singles.put(type, num);
return;
}
int count = singles.get(type);
count += num;
singles.put(type, count);
}
public void addRandom(DungeonRoom type, int weight){
multiple.put(type, weight);
}
@Override
public IDungeonRoom get(Random rand) {
if(!singles.isEmpty()) return this.getSingle(rand);
if(!multiple.isEmpty()) return this.getRandom(rand);
return DungeonRoom.getInstance(base);
}
private IDungeonRoom getRandom(Random rand){
Set<DungeonRoom> keyset = this.multiple.keySet();
if(keyset.isEmpty()) return null;
WeightedRandomizer<DungeonRoom> randomizer = new WeightedRandomizer<DungeonRoom>();
for(DungeonRoom room : keyset){
randomizer.add(new WeightedChoice<DungeonRoom>(room, multiple.get(room)));
}
DungeonRoom choice = randomizer.get(rand);
return DungeonRoom.getInstance(choice);
}
private IDungeonRoom getSingle(Random rand){
Set<DungeonRoom> keyset = this.singles.keySet();
if(keyset.isEmpty()) return null;
DungeonRoom[] rooms = keyset.toArray(new DungeonRoom[0]);
DungeonRoom type = rooms[rand.nextInt(rooms.length)];
if(this.singles.get(type) <= 1){
this.singles.remove(type);
} else {
this.singles.put(type, this.singles.get(type) - 1);
}
return DungeonRoom.getInstance(type);
}
@Override
public boolean equals(Object o){
DungeonFactory other = (DungeonFactory)o;
if(!this.base.equals(other.base)) return false;
if(!this.singles.equals(other.singles)) return false;
if(!this.multiple.equals(other.multiple)) return false;
return true;
}
public static DungeonFactory getRandom(Random rand, int numRooms) {
DungeonFactory rooms = new DungeonFactory();
rooms.base = DungeonRoom.CORNER;
for(int i = 0; i < numRooms; ++i){
DungeonRoom type = DungeonRoom.getRandomRoom(rand);
if(rand.nextBoolean()){
rooms.addRandom(type, 1);
} else {
rooms.addSingle(type, 1);
}
}
return rooms;
}
}