Skip to content
Snippets Groups Projects
Commit d088dc44 authored by Maxime Morge's avatar Maxime Morge :construction_worker:
Browse files

Add Environment, Robot and Target

parent f7d0ec5e
No related branches found
No related tags found
No related merge requests found
// Copyright (C) Maxime MORGE 2024
import org.scata.core.SingleAssignmentProblem
import org.scata.algorithm.CBAA
import org.scata.patrol.Environment
object Main {
def main(args: Array[String]): Unit = {
val nbWorkers = 4
val nbTasks = 3
val pb = SingleAssignmentProblem.randomProblem(nbWorkers, nbTasks)
val nbRobots= 4
val nbTargets = 3
val env = Environment.randomEnvironment(nbRobots, nbTargets)
println(env)
val pb = env.toSAP()
println(pb)
val cbaa = new CBAA(pb)
println(pb)
val solution = cbaa.solve()
......
......@@ -54,7 +54,7 @@ class CBAA(pb : SingleAssignmentProblem) {
}
// If there are valid tasks, select the one with the minimum cost
if (pb.tasks.exists(task => validTasks(task))) {
val bestTask = validTasks.filter(_._2).keys.minBy(task => pb.cost(worker, task))
val bestTask = validTasks.filter(_._2).keys.minBy(task => (pb.cost(worker, task), task.name))
if (debug) println(s"Worker ${worker.name} selects task ${bestTask.name} with cost ${pb.cost(worker, bestTask)}")
workerTaskList = workerTaskList.updated(worker, workerTaskList(worker).updated(bestTask, true))
winningBid = winningBid.updated(worker, winningBid(worker).updated(bestTask, (worker, pb.cost(worker, bestTask))))
......@@ -77,7 +77,7 @@ class CBAA(pb : SingleAssignmentProblem) {
// Find the minimum winning bid among the worker's neighbors (including itself)
val minWinningBid = neighbours(worker)
.map(neighbor => winningBid(neighbor)(task))
.minBy(_._2)
.minBy { case (winningWorker, cost) => (cost, winningWorker.name) }
println(s"Worker ${worker.name} minimum winning bid for task ${task.name} is ${minWinningBid}")
// Update the worker's winning bid for the task if a lower bid is found
if (minWinningBid._2 < winningBid(worker)(task)._2) {
......
// Copyright (C) Maxime MORGE, 2024
package org.scata.patrol
abstract class Entity(val name : String, val x : Int, val y: Int) extends Ordered[Entity]{
override def equals(that: Any): Boolean =
that match {
case that: Entity => that.canEqual(this) && this.name == that.name
case _ => false
}
private def canEqual(a: Any) : Boolean = a.isInstanceOf[Entity]
/**
* Returns 0 if this an that are the same, negative if this < that, and positive otherwise
* Entitys are sorted with their name
*/
def compare(that: Entity) : Int = {
if (this.name == that.name) return 0
else if (this.name > that.name) return 1
-1
}
}
// Copyright (C) Maxime MORGE, 2024
package org.scata.patrol
import org.scata.core.{SingleAssignmentProblem, Task, Worker}
import org.scata.core.SingleAssignmentProblem.MAX_COST
import scala.collection.SortedSet
import org.scata.utils.RandomUtils
/**
* Class representing an environment
* @param robots are the robots
* @param targets art the targets
*/
class Environment(val robots: SortedSet[Robot],
val targets: SortedSet[Target]) {
/**
* Returns a string describing the MASTAPlus problem
*/
override def toString: String = {
val robotsStr = robots.map(_.toString).mkString(", ")
val targetStr = targets.map(_.toString).mkString(", ")
s"Robots (${robots.size}): $robotsStr\n" +
s"Tasks (${targets.size}): $targetStr"
}
/**
* Returns the number of robots
*/
def m: Int = robots.size
/**
* Returns the number of targets
*/
def n: Int = targets.size
/**
* Generate a single assignment problem
*/
def toSAP(): SingleAssignmentProblem = {
if (n > m)
throw new RuntimeException("Cannot generate a single assignment problem since there are more targets than robots")
// Convert robots and targets into Workers and Tasks respectively
val workers: SortedSet[Worker] = robots.map(r => new Worker(r.name))
val tasks: SortedSet[Task] = targets.map(t => new Task(t.name))
// Create mapping from names to positions for cost calculation
val robotMap = robots.map(r => r.name -> (r.x, r.y)).toMap
val targetMap = targets.map(t => t.name -> (t.x, t.y)).toMap
// Compute cost using Euclidean distance
val cost: Map[(Worker, Task), Int] = (for {
worker <- workers
task <- tasks
} yield {
val (rx, ry) = robotMap(worker.name)
val (tx, ty) = targetMap(task.name)
val distance = math.abs(rx - tx) + math.abs(ry - ty)
((worker, task), distance.toInt)
}).toMap
new SingleAssignmentProblem(workers, tasks, cost)
}
}
/**
* Factory for SingleAssignmentProblem
*/
object Environment{
implicit val order : Ordering[Double] = Ordering.Double.TotalOrdering
// eventually Ordering.Double.IeeeOrdering
private val MAX_X : Int = 10 // Maximum width
private val MAX_Y : Int = 10 // Maximum height
/**
* Returns a random single-assignment problem instance with
* @param m robots
* @param n tasks
*/
def randomEnvironment(m: Int, n: Int): Environment = {
// Robots
val robots: SortedSet[Robot] = collection.immutable.SortedSet[Robot]() ++
(for (i <- 1 to m) yield new Robot(name = "r%02d".format(i),
RandomUtils.random(1, MAX_X),
RandomUtils.random(1, MAX_Y)
))
// Targets
val targets: SortedSet[Target] = collection.immutable.SortedSet[Target]() ++
(for (i <- 1 to n) yield new Target(name = "t%02d".format(i),
RandomUtils.random(0, MAX_X-1),
RandomUtils.random(0, MAX_Y-1)
))
new Environment(robots, targets)
}
}
// Copyright (C) Maxime MORGE, 2024
package org.scata.patrol
class Robot(name: String, x: Int, y: Int) extends Entity(name, x, y) {
override def toString: String = s"Robot($name, $x, $y)"
}
\ No newline at end of file
// Copyright (C) Maxime MORGE, 2024
package org.scata.patrol
class Target(name: String, x: Int, y: Int) extends Entity(name, x, y) {
override def toString: String = s"Target($name, $x, $y)"
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment