package ai.util; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Random; import rts.GameState; import rts.units.Unit; import rts.units.UnitAction; import util.Pair; /** * \brief Generates a list of all possible PlayerAction */ public class PlayerActionGenerator { GameState gs; PlayerAction base_ru; public List<Pair<Unit,List<UnitAction> > > choices; PlayerAction lastAction = null; long size = 1; long generated = 0; int choiceSizes[] = null; int currentChoice[] = null; boolean moreActions = true; public long getGenerated() { return generated; } public long getSize() { return size; } public PlayerAction getLastAction() { return lastAction; } public List<Pair<Unit,List<UnitAction> > > getChoices() { return choices; } public PlayerActionGenerator(GameState a_gs) { // Generate the reserved resources: base_ru = new PlayerAction(a_gs.getMapWidth(), a_gs.getMapHeight()); gs = a_gs; for(Unit u:gs.getMyUnits()) { if (u.hasAction()) { base_ru.mergeResourceUsage(u, u.getAction()); } } choices = new ArrayList<Pair<Unit,List<UnitAction> > >(); for(Unit u:gs.getMyUnits()) { if (!u.hasAction() && u.getActions().size() > 0) { choices.add(new Pair<Unit,List<UnitAction>>(u,u.getActions())); size*=u.getActions().size(); } } if (choices.size() == 0) { return; } //if (choices.size()==0) throw new Exception("Move generator created with no units that can execute actions!"); choiceSizes = new int[choices.size()]; currentChoice = new int[choices.size()]; int i = 0; for(Pair<Unit,List<UnitAction> > choice:choices) { choiceSizes[i] = choice.m_b.size(); currentChoice[i] = 0; i++; } } public void incrementCurrentChoice(int startPosition) { for(int i = 0;i<startPosition;i++) currentChoice[i] = 0; currentChoice[startPosition]++; if (currentChoice[startPosition]>=choiceSizes[startPosition]) { if (startPosition<currentChoice.length-1) { incrementCurrentChoice(startPosition+1); } else { moreActions = false; } } } public PlayerAction getNextAction(long cutOffTime) { int count = 0; while(moreActions) { boolean consistent = true; PlayerAction pa = new PlayerAction(base_ru); int i = choices.size(); if (i == 0) { return null; } //if (i==0) throw new Exception("Move generator created with no units that can execute actions!"); while(i>0) { i--; Pair<Unit,List<UnitAction> > unitChoices = choices.get(i); int choice = currentChoice[i]; Unit u = unitChoices.m_a; UnitAction ua = unitChoices.m_b.get(choice); if (pa.consistentResourceUsage(ua)) { pa.mergeResourceUsage(u, ua); pa.addUnitAction(u, ua); } else { consistent = false; break; } } incrementCurrentChoice(i); if (consistent) { lastAction = pa; generated++; return pa; } // check if we are over time (only check once every 1000 actions, since currenttimeMillis is a slow call): if (cutOffTime!=-1 && (count%1000==0) && System.currentTimeMillis()>cutOffTime) { lastAction = null; return null; } count++; } lastAction = null; return null; } public PlayerAction getRandom() { Random r = new Random(); PlayerAction pa = new PlayerAction(base_ru); for(Pair<Unit,List<UnitAction> > unitChoices:choices) { LinkedList<UnitAction> l = new LinkedList<UnitAction>(); l.addAll(unitChoices.m_b); Unit u = unitChoices.m_a; boolean consistent = false; do{ UnitAction ua = l.remove(r.nextInt(l.size())); if (pa.consistentResourceUsage(ua)) { pa.mergeResourceUsage(u, ua); pa.addUnitAction(u, ua); consistent = true; } }while(!consistent); } return pa; } public String toString() { String ret = "PlayerActionGenerator "; for(Pair<Unit,List<UnitAction> > choice:choices) { ret = ret + "(" + choice.m_a + "," + choice.m_b.size() + ") "; } return ret; } }