Slot#

One requirement instance on one task: a position that one resource fills, plus the resources eligible for it. Create slots with new Slot(id, task, allowed) or get them from SkillLayer.slots, then pass the list to Project#suggestAssignments. To build your own list from the project's tasks and resources, read Project#roster.

Declaration#

package org.dhtmlx.plen;

public class Slot extends ValueRecord implements DeepCloneable<Slot>

Constructors#

Slot(Id, Id, Vec<Id>)#

public Slot(Id id, Id task, Vec<Id> allowed)
public Slot(Id id, Id task, java.util.Collection<? extends Id> allowed)

Creates an empty slot with value = 1.0 and assignment = null. The Collection overload copies allowed into a new Vec, so List.of(...) works. A null collection stays null.

Parameters

Name Type Description
id Id Slot id.
task Id Task the slot belongs to.
allowed Vec<Id> or Collection<? extends Id> Eligible resources.

Fields#

Field Type Default Description
id Id set by the constructor Unique within one call. Echoed in SuggestStep.slot, SuggestResult.unfilled and SuggestResult.invalid. A new assignment that fills the slot takes this id.
task Id set by the constructor A scheduled leaf task.
allowed Vec<Id> set by the constructor Resources eligible for the slot. List order is the tie-break preference: on equal scores, an earlier resource wins.
value double 1.0 Units of the assignment created when the slot is filled. Finite and greater than 0.
assignment Id null The active assignment on task that fills the slot. null means the slot is empty.

The slot's state follows from these fields: with assignment set, the slot is valid when that assignment's resource is in allowed and broken when it isn't. SuggestOptions.targets picks which states a call works on.

The new assignment's id is the slot id, so after you commit a fill, pass withAssignment(slotId) on the next run to keep the slot bound. SkillLayer.slots does this for you.

For the checks run on each field, see Project#suggestAssignments.

Methods#

withId, withTask, withAllowed, withValue, withAssignment#

public Slot withId(Id value)
public Slot withTask(Id value)
public Slot withAllowed(Vec<Id> value)
public Slot withAllowed(java.util.Collection<? extends Id> value)
public Slot withValue(double value)
public Slot withAssignment(Id value)

Each setter assigns its field and returns this instance. The Collection overload of withAllowed copies the elements into a new Vec. A null collection sets the field to null.

Returns: this Slot.

deepClone#

public Slot deepClone()

Returns a new slot with the same field values and its own copy of the allowed list.

Returns: a new Slot.

Errors: NullPointerException when allowed is null.

copy#

public Slot copy()

Returns a shallow copy. The new slot shares the allowed list with the original.

Returns: a new Slot.

equals, hashCode, toString#

public boolean equals(Object other)
public int hashCode()
public String toString()

Inherited from ValueRecord. Two slots are equal when all five fields are equal. toString() prints every field, for logging.

Example#

Task A already has dev1. Task B needs a half-time person. Both slots accept dev1 or dev2.

import java.util.List;
import org.dhtmlx.plen.*;

public class SlotExample {
  static TaskData task(String id) {
    return new TaskData(Id.str(id))
        .withStartDate(Moment.fromYmdHm(2026, 8, 10, 0, 0))
        .withDuration(2.0);
  }

  public static void main(String[] args) throws Exception {
    ProjectData data = new ProjectData()
        .withTasks(List.of(task("A"), task("B")))
        .withResources(List.of(
            new ResourceData().withId(Id.str("dev1")),
            new ResourceData().withId(Id.str("dev2"))))
        .withAssignments(List.of(new AssignmentData()
            .withId(Id.str("aA"))
            .withTask(Id.str("A"))
            .withResource(Id.str("dev1"))
            .withValue(1.0)));
    data.config.useCalendars = false;

    Project project = new Project();
    project.solve(data, new SolveOptions());

    List<Id> devs = List.of(Id.str("dev1"), Id.str("dev2"));
    List<Slot> slots = List.of(
        // Filled slot: bound to the existing assignment on task A.
        new Slot(Id.str("sA"), Id.str("A"), devs).withAssignment(Id.str("aA")),
        // Empty slot: a half-time position on task B.
        new Slot(Id.str("sB"), Id.str("B"), devs).withValue(0.5));

    SuggestResult result = project.suggestAssignments(slots, new SuggestOptions());
    for (SuggestStep step : result.steps) {
      System.out.println(step.slot + " -> " + step.toResource); // sB -> dev2
    }
    System.out.println(result.changes.assignments.add);
    // [AssignmentData{id=sB, task=B, resource=dev2, value=0.5, offset=null, duration=null}]
  }
}