"github.com/nextmv-io/code/engines/route"
fleetEngine "github.com/nextmv-io/code/engines/route/fleet"
vehicleEngine "github.com/nextmv-io/code/engines/route/vehicle"
"github.com/nextmv-io/code/hop/run/cli"
"github.com/nextmv-io/code/hop/solve"
// Custom data to implement the VehicleUpdater interface.
type vehicleData struct {
Locations map[string]int `json:"locations,omitempty"`
// Reset locations before updating the vehicle state.
func (d vehicleData) Clone() route.VehicleUpdater {
d.Locations = make(map[string]int)
// Track the index in the route for each stop. Customize value function to
// incorporate the vehicle's score.
func (d vehicleData) Update(s vehicleEngine.State) (route.VehicleUpdater, *int) {
// Update a stop's route index.
for i := 1; i < len(route)-1; i++ {
stop := d.stops[route[i]]
// Apply correct vehicle score to the objective value.
vehicleID := s.Input().VehicleID.(string)
value := s.Value() * d.score[vehicleID]
// Custom data to implement the FleetUpdater interface.
Locations map[string]int `json:"locations,omitempty"`
vehicleValues map[string]int
// Reset global locations and vehicle state values before updating the fleet
func (d fleetData) Clone() route.FleetUpdater {
// Deep copy locations stored on fleet state.
locations := make(map[string]int, len(d.Locations))
for stopdID, i := range d.Locations {
// Deep copy the data required for the value function.
values := make(map[string]int, len(d.vehicleValues))
for vehicleID, i := range d.vehicleValues {
// Track the index of the route for each stop in each vehicle route. Customize
// value function to incorporate the custom vehicle engine's value.
func (d fleetData) Update(
vehicles ...vehicleEngine.State,
) (route.FleetUpdater, *int) {
for _, vehicle := range vehicles {
// Update locations based on the changes made on the vehicle state.
vehicleID := vehicle.Input().VehicleID.(string)
updater := vehicle.(route.Updater).Updater().(vehicleData)
for stopdID, i := range updater.Locations {
// Update value function information.
d.fleetValue -= d.vehicleValues[vehicleID]
d.vehicleValues[vehicleID] = value
d.fleetValue += d.vehicleValues[vehicleID]
// Remove unassigned locations.
for it := s.Unassigned().Iterator(); it.Next(); {
stop := d.stops[location]
delete(d.Locations, stop.ID)
// Struct to read from JSON in.
Stops []route.Stop `json:"stops,omitempty"`
Vehicles []string `json:"vehicles,omitempty"`
Score map[string]int `json:"score,omitempty"`
// Use the CLI runner to solve a Vehicle Routing Problem.
f := func(i input, opt solve.Options) (solve.Solver, error) {
v := vehicleData{stops: i.Stops, score: i.Score}
f := fleetData{stops: i.Stops}
router, err := route.NewRouter(
return router.Solver(opt)