edu.cwru.sepia.model.BestEffortModel.java Source code

Java tutorial

Introduction

Here is the source code for edu.cwru.sepia.model.BestEffortModel.java

Source

/**
 *  Strategy Engine for Programming Intelligent Agents (SEPIA)
Copyright (C) 2012 Case Western Reserve University
    
This file is part of SEPIA.
    
SEPIA is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
    
SEPIA is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
    
You should have received a copy of the GNU General Public License
along with SEPIA.  If not, see <http://www.gnu.org/licenses/>.
 */
package edu.cwru.sepia.model;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.commons.configuration.Configuration;

import edu.cwru.sepia.action.Action;
import edu.cwru.sepia.action.ActionQueue;
import edu.cwru.sepia.action.ActionResult;
import edu.cwru.sepia.action.ActionResultType;
import edu.cwru.sepia.action.ActionType;
import edu.cwru.sepia.action.DirectedAction;
import edu.cwru.sepia.action.LocatedAction;
import edu.cwru.sepia.action.LocatedProductionAction;
import edu.cwru.sepia.action.ProductionAction;
import edu.cwru.sepia.action.TargetedAction;
import edu.cwru.sepia.model.state.Direction;
import edu.cwru.sepia.model.state.ResourceNode;
import edu.cwru.sepia.model.state.State;
import edu.cwru.sepia.model.state.StateCreator;
import edu.cwru.sepia.model.state.Template;
import edu.cwru.sepia.model.state.Unit;
import edu.cwru.sepia.model.state.UnitTemplate;
import edu.cwru.sepia.model.state.UpgradeTemplate;
import edu.cwru.sepia.pathing.DurativePlanner;
import edu.cwru.sepia.util.SerializerUtil;

/**
 * A Model that attempts the best effort. <br>
 * A branch of SimpleModel with some added features: durative actions and turn
 * taking. <br>
 * This model is sequential, processing most actions one at a time. Because of
 * this, it resolves conflicts by allowing them to proceed on a
 * first-come-first-served basis. <br>
 */
public class BestEffortModel extends AbstractDurativeModel {
    private static final long serialVersionUID = -8289868580233478749L;

    private final String NUM_ATTEMPTS = "environment.model.numattempts";

    private int numAttempts;

    public BestEffortModel(State init, StateCreator restartTactic, Configuration configuration) {
        super(init, restartTactic, configuration, Logger.getLogger(BestEffortModel.class.getCanonicalName()));
        this.numAttempts = configuration.getInt(NUM_ATTEMPTS, 2);
    }

    @SuppressWarnings("incomplete-switch")
    @Override
    public void executeStep() {

        // Set each agent to have no task
        for (Unit u : state.getUnits().values()) {
            u.deprecateOldView();
        }
        // Set each template to not keep the old view
        for (Integer player : state.getPlayers())
            for (@SuppressWarnings("rawtypes")
            Template t : state.getTemplates(player).values())
                t.deprecateOldView();

        // Run the Action
        for (Integer player : state.getPlayers()) {
            // hedge against players entering the state for some reason
            if (!queuedActions.containsKey(player)) {
                queuedActions.put(player, new HashMap<Integer, ActionQueue>());
            }
            if (turnTracker == null || turnTracker.isPlayersTurn(player)) {
                Iterator<ActionQueue> queuedActItr = queuedActions.get(player).values().iterator();
                while (queuedActItr.hasNext()) {
                    ActionQueue queuedAct = queuedActItr.next();
                    if (logger.isLoggable(Level.FINE))
                        logger.fine("Doing full action: " + queuedAct.getFullAction());
                    // Pull out the primitive
                    if (!queuedAct.hasNext())
                        continue;
                    Action a = queuedAct.popPrimitive();
                    if (logger.isLoggable(Level.FINE))
                        logger.fine("Doing primitive action: " + a);
                    // Execute it
                    Unit u = state.getUnit(a.getUnitId());
                    if (u == null)
                        continue;
                    // Set the tasks and grab the common features
                    int x = u.getXPosition();
                    int y = u.getYPosition();
                    int xPrime = 0;
                    int yPrime = 0;
                    if (a instanceof DirectedAction) {
                        Direction d = ((DirectedAction) a).getDirection();
                        xPrime = x + d.xComponent();
                        yPrime = y + d.yComponent();
                    } else if (a instanceof LocatedAction) {
                        xPrime = x + ((LocatedAction) a).getX();
                        yPrime = y + ((LocatedAction) a).getY();
                    }

                    // Gather the last of the information and actually execute
                    // the actions
                    int timesTried = 0;
                    boolean failedTry = true;
                    boolean wrongType = false;
                    boolean fullIsPrimitive = ActionType.isPrimitive(a.getType());
                    boolean incompletePrimitive;
                    /*
                     * recalculate and try again once if it has failed, so long
                     * as the full action is not primitive (since primitives
                     * will recalculate to the same as before) and not the wrong
                     * type (since something is wrong if it is the wrong type)
                     */
                    do {
                        timesTried++;
                        failedTry = false;
                        incompletePrimitive = false;
                        switch (a.getType()) {
                        case PRIMITIVEMOVE:
                            if (!(a instanceof DirectedAction)) {
                                wrongType = true;
                                break;
                            }
                            if (accessible(u, xPrime, yPrime)) {
                                int newdurativeamount;
                                if (a.equals(u.getActionProgressPrimitive())) {
                                    newdurativeamount = u.getActionProgressAmount() + 1;
                                } else {
                                    newdurativeamount = 1;
                                }
                                Direction d = ((DirectedAction) a).getDirection();
                                boolean willcompletethisturn = newdurativeamount == DurativePlanner
                                        .calculateMoveDuration(u, u.getXPosition(), u.getYPosition(), d, state);
                                // if it will finish, then execute the atomic
                                // action
                                if (willcompletethisturn) {
                                    state.moveUnit(u, d);
                                    u.resetDurative();
                                } else {
                                    incompletePrimitive = true;
                                    u.setDurativeStatus(a, newdurativeamount);
                                }
                            } else {
                                failedTry = true;
                                queuedAct.resetPrimitives(calculatePrimitives(queuedAct.getFullAction()));
                            }
                            break;
                        case PRIMITIVEGATHER:
                            if (!(a instanceof DirectedAction)) {
                                wrongType = true;
                                break;
                            }
                            boolean failed = false;
                            ResourceNode resource = state.resourceAt(xPrime, yPrime);
                            if (resource == null) {
                                failed = true;
                            } else if (!u.canGather()) {
                                failed = true;
                            } else {
                                int newdurativeamount;
                                if (a.equals(u.getActionProgressPrimitive())) {
                                    newdurativeamount = u.getActionProgressAmount() + 1;
                                } else {
                                    newdurativeamount = 1;
                                }
                                boolean willcompletethisturn = newdurativeamount == DurativePlanner
                                        .calculateGatherDuration(u, resource);
                                // if it will finish, then execute the atomic
                                // action
                                if (willcompletethisturn) {
                                    int amountPickedUp = resource.reduceAmountRemaining(
                                            u.getTemplate().getGatherRate(resource.getType().getResource()));
                                    u.setCargo(resource.getResourceType(), amountPickedUp);
                                    history.recordResourcePickup(u, resource, amountPickedUp, state);
                                    u.resetDurative();
                                } else {
                                    incompletePrimitive = true;
                                    u.setDurativeStatus(a, newdurativeamount);
                                }
                            }
                            if (failed) {
                                failedTry = true;
                                queuedAct.resetPrimitives(calculatePrimitives(queuedAct.getFullAction()));
                            }
                            break;
                        case PRIMITIVEDEPOSIT:
                            if (!(a instanceof DirectedAction)) {
                                wrongType = true;
                                break;
                            }
                            // only can do a primitive if you are in the right
                            // position
                            Unit townHall = state.unitAt(xPrime, yPrime);
                            boolean canAccept = false;
                            if (townHall != null && townHall.getPlayer() == u.getPlayer()) {
                                if (townHall.getTemplate().canAccept(u.getCurrentCargoType()))
                                    canAccept = true;
                            }
                            if (!canAccept) {
                                failedTry = true;
                                queuedAct.resetPrimitives(calculatePrimitives(queuedAct.getFullAction()));
                                break;
                            } else {
                                int newdurativeamount;
                                if (a.equals(u.getActionProgressPrimitive())) {
                                    newdurativeamount = u.getActionProgressAmount() + 1;
                                } else {
                                    newdurativeamount = 1;
                                }
                                boolean willcompletethisturn = newdurativeamount == DurativePlanner
                                        .calculateDepositDuration(u, townHall);
                                // if it will finish, then execute the atomic
                                // action
                                if (willcompletethisturn) {
                                    int agent = u.getPlayer();
                                    history.recordResourceDropoff(u, townHall, state);
                                    state.addResourceAmount(agent, u.getCurrentCargoType(),
                                            u.getCurrentCargoAmount());
                                    u.clearCargo();
                                    u.resetDurative();
                                } else {
                                    incompletePrimitive = true;
                                    u.setDurativeStatus(a, newdurativeamount);
                                }
                                break;
                            }
                        case PRIMITIVEATTACK:
                            if (!(a instanceof TargetedAction)) {
                                wrongType = true;
                                break;
                            }
                            Unit target = state.getUnit(((TargetedAction) a).getTargetId());
                            if (target != null) {
                                if (u.getTemplate().getRange() >= u.getBounds().distanceTo(target.getBounds())) {
                                    int newdurativeamount;
                                    if (a.equals(u.getActionProgressPrimitive())) {
                                        newdurativeamount = u.getActionProgressAmount() + 1;
                                    } else {
                                        newdurativeamount = 1;
                                    }
                                    boolean willcompletethisturn = newdurativeamount == DurativePlanner
                                            .calculateAttackDuration(u, target);
                                    // if it will finish, then execute the
                                    // atomic action
                                    if (willcompletethisturn) {
                                        int damage = calculateDamage(u, target);
                                        history.recordDamage(u, target, damage, state);
                                        target.setHP(Math.max(target.getCurrentHealth() - damage, 0));
                                        u.resetDurative();
                                    } else {
                                        incompletePrimitive = true;
                                        u.setDurativeStatus(a, newdurativeamount);
                                    }
                                } else // out of range
                                {
                                    failedTry = true;
                                    queuedAct.resetPrimitives(calculatePrimitives(queuedAct.getFullAction()));
                                }
                            } else {
                                failedTry = true;
                                queuedAct.resetPrimitives(calculatePrimitives(queuedAct.getFullAction()));
                            }
                            break;
                        case PRIMITIVEBUILD: {
                            if (!(a instanceof ProductionAction)) {
                                wrongType = true;
                                break;
                            }
                            if (queuedAct.getFullAction().getType() == ActionType.COMPOUNDBUILD
                                    && queuedAct.getFullAction() instanceof LocatedProductionAction) {
                                LocatedProductionAction fullbuild = (LocatedProductionAction) queuedAct
                                        .getFullAction();
                                if (fullbuild.getX() != u.getXPosition() || fullbuild.getY() != u.getYPosition()) {
                                    failedTry = true;
                                    queuedAct.resetPrimitives(calculatePrimitives(queuedAct.getFullAction()));
                                    break;
                                }
                            }
                            UnitTemplate template = (UnitTemplate) state
                                    .getTemplate(((ProductionAction) a).getTemplateId());
                            if (u.getTemplate().canProduce(template)) {
                                boolean prerequisitesMet = true;
                                // check if the prerequisites for the template's
                                // production are met
                                for (String templateName : template.getBuildPrerequisites()) {
                                    if (!state.hasUnit(u.getPlayer(), templateName)) {
                                        prerequisitesMet = false;
                                        break;
                                    }
                                }
                                if (prerequisitesMet) {
                                    for (String templateName : template.getUpgradePrerequisites()) {
                                        if (!state.hasUpgrade(u.getPlayer(), templateName)) {
                                            prerequisitesMet = false;
                                            break;
                                        }
                                    }
                                }
                                if (prerequisitesMet) {
                                    int newdurativeamount = a.equals(u.getActionProgressPrimitive())
                                            ? u.getActionProgressAmount() + 1
                                            : 1;
                                    boolean willcompletethisturn = newdurativeamount == DurativePlanner
                                            .calculateProductionDuration(u, template);
                                    // if it will finish, then execute the
                                    // atomic action
                                    if (willcompletethisturn) {
                                        Unit building = template.produceInstance(state);
                                        int[] newxy = state.getClosestPosition(x, y);
                                        if (state.tryProduceUnit(building, newxy[0], newxy[1])) {
                                            history.recordBirth(building, u, state);
                                        }
                                        u.resetDurative();
                                    } else {
                                        incompletePrimitive = true;
                                        u.setDurativeStatus(a, newdurativeamount);
                                    }
                                } else // didn't meet prerequisites
                                {
                                    failedTry = true;
                                }
                            } else // it can't produce the appropriate thing
                            {
                                failedTry = true;
                            }

                            break;
                        }
                        case PRIMITIVEPRODUCE: {
                            if (!(a instanceof ProductionAction)) {
                                wrongType = true;
                                break;
                            }
                            Template<?> template = state.getTemplate(((ProductionAction) a).getTemplateId());
                            // check if it is even capable of producing the
                            // template
                            if (u.getTemplate().canProduce(template)) {
                                boolean prerequisitesMet = true;
                                // check if the prerequisites for the template's
                                // production are met
                                for (String templateName : template.getBuildPrerequisites()) {
                                    if (!state.hasUnit(u.getPlayer(), templateName)) {
                                        prerequisitesMet = false;
                                        break;
                                    }
                                }
                                if (prerequisitesMet) {
                                    for (String templateName : template.getUpgradePrerequisites()) {
                                        if (!state.hasUpgrade(u.getPlayer(), templateName)) {
                                            prerequisitesMet = false;
                                            break;
                                        }
                                    }
                                }
                                if (prerequisitesMet) {
                                    int newdurativeamount = a.equals(u.getActionProgressPrimitive())
                                            ? u.getActionProgressAmount() + 1
                                            : 1;
                                    boolean willcompletethisturn = newdurativeamount == DurativePlanner
                                            .calculateProductionDuration(u, template);
                                    // if it will finish, then execute the
                                    // atomic action
                                    if (willcompletethisturn) {
                                        if (template instanceof UnitTemplate) {
                                            Unit produced = ((UnitTemplate) template).produceInstance(state);
                                            int[] newxy = state.getClosestPosition(x, y);
                                            if (state.tryProduceUnit(produced, newxy[0], newxy[1])) {
                                                history.recordBirth(produced, u, state);
                                            }
                                        } else if (template instanceof UpgradeTemplate) {
                                            UpgradeTemplate upgradetemplate = ((UpgradeTemplate) template);
                                            if (state.tryProduceUpgrade(upgradetemplate.produceInstance(state))) {
                                                history.recordUpgrade(upgradetemplate, u, state);
                                            }
                                        }
                                    } else {
                                        incompletePrimitive = true;
                                        u.setDurativeStatus(a, newdurativeamount);
                                    }
                                } else { // prerequisites not met
                                    failedTry = true;
                                }
                            } else// can't produce it
                            {
                                failedTry = true;
                            }
                            break;
                        }
                        case FAILED: {
                            failedTry = true;
                            queuedAct.resetPrimitives(calculatePrimitives(queuedAct.getFullAction()));
                            break;
                        }
                        case FAILEDPERMANENTLY: {
                            break;
                        }
                        }

                        // Record results

                        ActionResultType primitiveFeedback = null;
                        ActionResultType compoundFeedback = null;
                        boolean removeAction = false;
                        if (wrongType) {
                            // if it had the wrong type, then either the planner
                            // is bugged (unlikely) or the user provided a bad
                            // primitive action
                            // either way, record it as failed and toss it
                            compoundFeedback = ActionResultType.INVALIDTYPE;
                            removeAction = true;
                        } else if (!failedTry && a.getType() != ActionType.FAILEDPERMANENTLY) {
                            primitiveFeedback = incompletePrimitive ? ActionResultType.INCOMPLETE
                                    : ActionResultType.COMPLETED;
                            if (!incompletePrimitive && !queuedAct.hasNext()) {
                                compoundFeedback = ActionResultType.COMPLETED;
                                removeAction = true;
                            } else {
                                compoundFeedback = ActionResultType.INCOMPLETE;
                            }
                        } else if (a.getType() == ActionType.FAILEDPERMANENTLY || failedTry && fullIsPrimitive) {
                            compoundFeedback = ActionResultType.FAILED;
                            primitiveFeedback = ActionResultType.FAILED;
                            removeAction = true;

                        } else {
                            compoundFeedback = ActionResultType.INCOMPLETEMAYBESTUCK;
                            primitiveFeedback = ActionResultType.FAILED;
                        }
                        if (compoundFeedback != null) {
                            history.recordCommandFeedback(u.getPlayer(), state.getTurnNumber(),
                                    new ActionResult(queuedAct.getFullAction(), compoundFeedback));
                        }
                        if (primitiveFeedback != null) {
                            history.recordPrimitiveFeedback(u.getPlayer(), state.getTurnNumber(),
                                    new ActionResult(a, primitiveFeedback));
                        }
                        if (removeAction) {
                            queuedActItr.remove();
                        }
                    } while (timesTried < numAttempts && failedTry && !fullIsPrimitive && !wrongType);
                }
            } // end if it is the player's turn
        }

        // Take all the dead units and clear them
        // Find the dead units
        Map<Integer, Unit> allunits = state.getUnits();
        List<Integer> dead = new ArrayList<Integer>(allunits.size());
        for (Unit u : allunits.values()) {
            if (u.getCurrentHealth() <= 0) {
                history.recordDeath(u, state);
                dead.add(u.id);
            }
        }
        // Remove them
        for (int uid : dead) {
            state.removeUnit(uid);
        }
        // Take all of the used up resources and get rid of them
        List<ResourceNode> allnodes = state.getResources();
        List<Integer> usedup = new ArrayList<Integer>(allnodes.size());
        for (ResourceNode r : allnodes) {
            if (r.getAmountRemaining() <= 0) {
                history.recordResourceNodeExhaustion(r, state);
                usedup.add(r.id);
            }
        }
        // Remove the used up resource nodes
        for (int rid : usedup) {

            state.removeResourceNode(rid);
        }

        state.incrementTurn();
    }

    public void save(String filename) {
        SerializerUtil.storeState(filename, state);
    }

}