All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.badlogic.gdx.ai.fma.SoftRoleSlotAssignmentStrategy Maven / Gradle / Ivy

There is a newer version: 1.8.2
Show newest version
/*******************************************************************************
 * Copyright 2014 See AUTHORS file.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/

package com.badlogic.gdx.ai.fma;

import com.badlogic.gdx.math.Vector;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.BooleanArray;
import com.badlogic.gdx.utils.GdxRuntimeException;

/** {@code SoftRoleSlotAssignmentStrategy} is a concrete implementation of {@link BoundedSlotAssignmentStrategy} that supports soft
 * roles, i.e. roles that can be broken. Rather than a member having a list of roles it can fulfill, it has a set of values
 * representing how difficult it would find it to fulfill every role. The value is known as the slot cost. To make a slot
 * impossible for a member to fill, its slot cost should be infinite (you can even set a threshold to ignore all slots whose cost
 * is too high; this will reduce computation time when several costs are exceeding). To make a slot ideal for a member, its slot
 * cost should be zero. We can have different levels of unsuitable assignment for one member.
 * 

* Slot costs do not necessarily have to depend only on the member and the slot roles. They can be generalized to include any * difficulty a member might have in taking up a slot. If a formation is spread out, for example, a member may choose a slot that * is close by over a more distant slot. Distance can be directly used as a slot cost. *

* IMPORTANT NOTES: *

    *
  • In order for the algorithm to work properly the slot costs can not be negative.
  • *
  • This algorithm is often not fast enough to be used regularly. However, slot assignment happens relatively seldom (when the * player selects a new pattern, for example, or adds a member to the formation, or a member is removed from the formation).
  • *
* * @param Type of vector, either 2D or 3D, implementing the {@link Vector} interface * * @author davebaol */ public class SoftRoleSlotAssignmentStrategy> extends BoundedSlotAssignmentStrategy { protected SlotCostProvider slotCostProvider; protected float costThreshold; private BooleanArray filledSlots; /** Creates a {@code SoftRoleSlotAssignmentStrategy} with the given slot cost provider and no cost threshold. * @param slotCostProvider the slot cost provider */ public SoftRoleSlotAssignmentStrategy (SlotCostProvider slotCostProvider) { this(slotCostProvider, Float.POSITIVE_INFINITY); } /** Creates a {@code SoftRoleSlotAssignmentStrategy} with the given slot cost provider and cost threshold. * @param slotCostProvider the slot cost provider * @param costThreshold is a slot-cost limit, beyond which a slot is considered to be too expensive to consider occupying. */ public SoftRoleSlotAssignmentStrategy (SlotCostProvider slotCostProvider, float costThreshold) { this.slotCostProvider = slotCostProvider; this.costThreshold = costThreshold; this.filledSlots = new BooleanArray(); } @Override public void updateSlotAssignments (Array> assignments) { // Holds a list of member and slot data for each member. Array> memberData = new Array>(); // Compile the member data int numberOfAssignments = assignments.size; for (int i = 0; i < numberOfAssignments; i++) { SlotAssignment assignment = assignments.get(i); // Create a new member datum, and fill it MemberAndSlots datum = new MemberAndSlots(assignment.member); // Add each valid slot to it for (int j = 0; j < numberOfAssignments; j++) { // Get the cost of the slot float cost = slotCostProvider.getCost(assignment.member, j); // Make sure the slot is valid if (cost >= costThreshold) continue; SlotAssignment slot = assignments.get(j); // Store the slot information CostAndSlot slotDatum = new CostAndSlot(cost, slot.slotNumber); datum.costAndSlots.add(slotDatum); // Add it to the member's ease of assignment datum.assignmentEase += 1f / (1f + cost); } // Add member datum memberData.add(datum); } // Reset the array to keep track of which slots we have already filled. if (numberOfAssignments > filledSlots.size) filledSlots.ensureCapacity(numberOfAssignments - filledSlots.size); filledSlots.size = numberOfAssignments; for (int i = 0; i < numberOfAssignments; i++) filledSlots.set(i, false); // Arrange members in order of ease of assignment, with the least easy first. memberData.sort(); MEMBER_LOOP: for (int i = 0; i < memberData.size; i++) { MemberAndSlots memberDatum = memberData.get(i); // Choose the first slot in the list that is still empty (non-filled) memberDatum.costAndSlots.sort(); int m = memberDatum.costAndSlots.size; for (int j = 0; j < m; j++) { int slotNumber = memberDatum.costAndSlots.get(j).slotNumber; // Check if this slot is valid if (!filledSlots.get(slotNumber)) { // Fill this slot SlotAssignment slot = assignments.get(slotNumber); slot.member = memberDatum.member; slot.slotNumber = slotNumber; // Reserve the slot filledSlots.set(slotNumber, true); // Go to the next member continue MEMBER_LOOP; } } // If we reach here, it's because a member has no valid assignment. // // TODO // Some sensible action should be taken, such as reporting to the player. throw new GdxRuntimeException("SoftRoleSlotAssignmentStrategy cannot find valid slot assignment for member " + memberDatum.member); } } static class CostAndSlot> implements Comparable> { float cost; int slotNumber; public CostAndSlot (float cost, int slotNumber) { this.cost = cost; this.slotNumber = slotNumber; } @Override public int compareTo (CostAndSlot other) { return cost < other.cost ? -1 : (cost > other.cost ? 1 : 0); } } static class MemberAndSlots> implements Comparable> { FormationMember member; float assignmentEase; Array> costAndSlots; public MemberAndSlots (FormationMember member) { this.member = member; this.assignmentEase = 0f; this.costAndSlots = new Array>(); } @Override public int compareTo (MemberAndSlots other) { return assignmentEase < other.assignmentEase ? -1 : (assignmentEase > other.assignmentEase ? 1 : 0); } } public interface SlotCostProvider> { public float getCost (FormationMember member, int slotNumber); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy