diff --git a/cmd/simu/main.go b/cmd/simu/main.go index c29a1f66f5a6b3a3bf7c3dee0a49389e68be6697..9c17dbaeda87fa72e40546a19735b10ffc6b5cd1 100644 --- a/cmd/simu/main.go +++ b/cmd/simu/main.go @@ -6,7 +6,7 @@ import ( ) func main() { - s := simulation.NewSimulation(1, -1, 600*time.Second) + s := simulation.NewSimulation(20, -1, 600*time.Second) //go simulation.StartAPI(s) s.Run() } diff --git a/internal/algorithms/astar.go b/internal/algorithms/astar.go index 3ccdd128e0962ede908bfa2141dd294906286d9a..d1fc5062c3e54db8733201f9de67c1036b26b6e1 100644 --- a/internal/algorithms/astar.go +++ b/internal/algorithms/astar.go @@ -2,12 +2,12 @@ package algorithms import ( "container/heap" + "math/rand" ) /* * Utilisation de l'algorithme A* pour les déplacements * //TODO: Peut-être gérer un passage par référence et non par copie - * //TODO: faire des points de repère */ type Node struct { row, col, cost, heuristic, width, height, orientation int @@ -30,6 +30,10 @@ func (nd *Node) Or() int { return nd.orientation } +func (nd *Node) Heuristic() int { + return nd.heuristic +} + type PriorityQueue []*Node func (pq PriorityQueue) Len() int { return len(pq) } @@ -55,7 +59,10 @@ func (pq *PriorityQueue) Pop() interface{} { return item } -func FindPath(matrix [20][20]string, start, end Node, forbidenCell Node) []Node { +type ZoneID int +type Coord [2]int + +func FindPath(matrix [20][20]string, start, end Node, forbidenCell Node, orientation bool) []Node { pq := make(PriorityQueue, 0) heap.Init(&pq) @@ -64,7 +71,7 @@ func FindPath(matrix [20][20]string, start, end Node, forbidenCell Node) []Node parents := make(map[Node]Node) closestPoint := start // Initialisation avec le point de départ - closestDistance := heuristic(start.row, start.col, end) + closestDistance := Heuristic(start.row, start.col, end) foundPath := false @@ -72,7 +79,7 @@ func FindPath(matrix [20][20]string, start, end Node, forbidenCell Node) []Node current := heap.Pop(&pq).(*Node) // Mise à jour du point le plus proche si le point actuel est plus proche - currentDistance := heuristic(current.row, current.col, end) + currentDistance := Heuristic(current.row, current.col, end) if currentDistance < closestDistance { closestPoint = *current closestDistance = currentDistance @@ -90,7 +97,7 @@ func FindPath(matrix [20][20]string, start, end Node, forbidenCell Node) []Node visited[*current] = true - neighbors := getNeighbors(matrix, *current, end, forbidenCell) + neighbors := getNeighbors(matrix, *current, end, forbidenCell, orientation) for _, neighbor := range neighbors { if !visited[*neighbor] { parents[*neighbor] = *current @@ -112,25 +119,40 @@ func FindPath(matrix [20][20]string, start, end Node, forbidenCell Node) []Node return nil // Aucun chemin trouvé } -func getNeighbors(matrix [20][20]string, current, end Node, forbiddenCell Node) []*Node { +func getNeighbors(matrix [20][20]string, current, end Node, forbiddenCell Node, orientation bool) []*Node { //fmt.Println("okk") neighbors := make([]*Node, 0) - // Possible moves: up, down, left, right, rotate (clockwise) + // Possible moves: up, down, left, right possibleMoves := [][]int{{-1, 0}, {1, 0}, {0, -1}, {0, 1}} for _, move := range possibleMoves { newRow, newCol := current.row+move[0], current.col+move[1] - for orientation := 0; orientation < 4; orientation++ { - current.orientation = orientation - // fmt.Println(orientation) - // Check if the new position is valid, considering agent dimensions and rotation - if isValidMove(matrix, current, forbiddenCell, newRow, newCol) { + if orientation { + for or := 0; or < 4; or++ { + current.orientation = or + //fmt.Println(orientation) + //Check if the new position is valid, considering agent dimensions and rotation + if isValidMove(matrix, current, forbiddenCell, newRow, newCol, orientation) { + neighbors = append(neighbors, &Node{ + row: newRow, + col: newCol, + cost: current.cost + 1, + heuristic: Heuristic(newRow, newCol, end), + width: current.width, + height: current.height, + orientation: current.orientation, + }) + } + } + + } else { + if isValidMove(matrix, current, forbiddenCell, newRow, newCol, orientation) { neighbors = append(neighbors, &Node{ row: newRow, col: newCol, cost: current.cost + 1, - heuristic: heuristic(newRow, newCol, end), + heuristic: Heuristic(newRow, newCol, end), width: current.width, height: current.height, orientation: current.orientation, @@ -143,9 +165,11 @@ func getNeighbors(matrix [20][20]string, current, end Node, forbiddenCell Node) return neighbors } -func heuristic(row, col int, end Node) int { +func Heuristic(row, col int, end Node) int { // Heuristique simple : distance de Manhattan - return abs(row-end.row) + abs(col-end.col) + // On introduit de l'aléatoire pour ajouter de la diversité dans la construction des chemins + // On évite d'avoir tout le temps le même chemin pour un même point de départ et d'arrivé + return abs(row-end.row) + abs(col-end.col) + rand.Intn(3) } func abs(x int) int { @@ -155,7 +179,7 @@ func abs(x int) int { return x } -func isValidMove(matrix [20][20]string, current Node, forbiddenCell Node, newRow, newCol int) bool { +func isValidMove(matrix [20][20]string, current Node, forbiddenCell Node, newRow, newCol int, orientation bool) bool { // Check if the new position is within the bounds of the matrix if newRow < 0 || newRow >= len(matrix) || newCol < 0 || newCol >= len(matrix[0]) { return false @@ -165,31 +189,38 @@ func isValidMove(matrix [20][20]string, current Node, forbiddenCell Node, newRow if forbiddenCell.row == newRow && forbiddenCell.col == newCol { return false } + // Check if the absolute coordinates overlap with obstacles in the matrix + if matrix[newRow][newCol] == "Q" || matrix[newRow][newCol] == "X" { + return false + } // Check if the agent fits in the new position, considering its dimensions and rotation - lRowBound, uRowBound, lColBound, uColBound := calculateBounds(newRow, newCol, current.width, current.height, current.orientation) + if orientation { + lRowBound, uRowBound, lColBound, uColBound := calculateBounds(newRow, newCol, current.width, current.height, current.orientation) - for i := lRowBound; i < uRowBound; i++ { - for j := lColBound; j < uColBound; j++ { + for i := lRowBound; i < uRowBound; i++ { + for j := lColBound; j < uColBound; j++ { - // Calculate the absolute coordinates in the matrix - absRow, absCol := i, j + // Calculate the absolute coordinates in the matrix + absRow, absCol := i, j - // Check if the absolute coordinates are within the bounds of the matrix - if absRow < 0 || absRow >= len(matrix) || absCol < 0 || absCol >= len(matrix[0]) { - return false - } + // Check if the absolute coordinates are within the bounds of the matrix + if absRow < 0 || absRow >= len(matrix) || absCol < 0 || absCol >= len(matrix[0]) { + return false + } - // Check if the absolute coordinates overlap with forbidden cells or obstacles - if forbiddenCell.row == absRow && forbiddenCell.col == absCol { - return false - } + // Check if the absolute coordinates overlap with forbidden cells or obstacles + if forbiddenCell.row == absRow && forbiddenCell.col == absCol { + return false + } - // Check if the absolute coordinates overlap with obstacles in the matrix - if matrix[absRow][absCol] == "Q" || matrix[absRow][absCol] == "X" { - return false + // Check if the absolute coordinates overlap with obstacles in the matrix + if matrix[absRow][absCol] == "Q" || matrix[absRow][absCol] == "X" { + return false + } } } + } return true diff --git a/internal/simulation/agent.go b/internal/simulation/agent.go index 5013677e8e57621c63d3b33403a019d355b3450f..2d9d0308b0e1e3cf2203a9f1282a388c1580f6e0 100644 --- a/internal/simulation/agent.go +++ b/internal/simulation/agent.go @@ -6,15 +6,18 @@ package simulation * // TODO: Gérer les moments où les agents font du quasi-sur place car ils ne peuvent plus bouger * // TODO: Il arrive encore que certains agents soient bloqués, mais c'est quand il n'y a aucun mouvement possible. * // Il faudrait faire en sorte que les agents bougent et laisse passer les autres - * */ import ( + //"fmt" + "log" "math/rand" + + //"math" + //"math/rand" alg "metrosim/internal/algorithms" "time" - "fmt" ) type Action int64 @@ -24,6 +27,7 @@ const ( Mark Wait Move + Disapear ) type Coord [2]int @@ -46,6 +50,9 @@ type Agent struct { width int height int orientation int + path []alg.Node + // visitedPanneaux map[alg.Node]bool + // visiting *alg.Node } type Behavior interface { @@ -57,7 +64,13 @@ type Behavior interface { func NewAgent(id string, env *Environment, syncChan chan int, vitesse time.Duration, force int, politesse bool, behavior Behavior, departure, destination Coord, width, height int) *Agent { isOn := make(map[Coord]string) saveCells(&env.station, isOn, departure, width, height, 0) - return &Agent{AgentID(id), vitesse, force, politesse, departure, departure, destination, behavior, env, syncChan, Noop, isOn, false, width, height, 0} + // Enregistrement des panneaux menant à la zone + // visitedPanneaux := make(map[alg.Node]bool, len(env.panneaux[env.zones[destination]])) + // for _, panneau := range env.panneaux[env.zones[destination]] { + // visitedPanneaux[panneau] = false + // } + // visiting := alg.NewNode(destination[0], destination[1], 0, HeuristicWithObstacles(departure, destination, env), 0, 0) + return &Agent{AgentID(id), vitesse, force, politesse, departure, departure, destination, behavior, env, syncChan, Noop, isOn, false, width, height, 0, make([]alg.Node, 0)} } func (ag *Agent) ID() AgentID { @@ -75,6 +88,10 @@ func (ag *Agent) Start() { ag.behavior.Deliberate(ag) ag.behavior.Act(ag) ag.syncChan <- step + if ag.decision == Disapear { + ag.env.RemoveAgent(*ag) + return + } } }() } @@ -85,62 +102,79 @@ func (ag *Agent) Act(env *Environment) { } } -func IsMovementSafe(path []alg.Node, agt *Agent, env *Environment) bool { +func IsMovementSafe(path []alg.Node, agt *Agent, env *Environment) (bool, int) { // Détermine si le movement est faisable if len(path) <= 0 { - return false + return false, agt.orientation } + // Calcul des bornes de position de l'agent avant mouvement + infRow, supRow, infCol, supCol := calculateBounds(agt.position, agt.width, agt.height, agt.orientation) // Simulation du déplacement ag := *agt ag.position = Coord{path[0].Row(), path[0].Col()} - rotateAgent(&ag, path[0].Or()) - - // Calcul des bornes de position de l'agent avant mouvement - infRow, supRow, infCol, supCol := calculateBounds(agt.position, agt.width, agt.height, agt.orientation) - - // Calcul des bornes de position de l'agent après mouvement - borneInfRow, borneSupRow, borneInfCol, borneSupCol := calculateBounds(ag.position, ag.width, ag.height, ag.orientation) - - for i := borneInfRow; i < borneSupRow; i++ { - for j := borneInfCol; j < borneSupCol; j++ { - if !(j >= infCol && j < supCol && i >= infRow && i < supRow) && (env.station[i][j] != "B" && env.station[i][j] != "_") { - // Si on est sur un agent, en dehors de la zone qu'occupe l'agent avant déplacement, on est bloqué - return false + for or := 0; or < 4; or++ { + rotateAgent(&ag, or) + safe := true + + // Calcul des bornes de position de l'agent après mouvement + + borneInfRow, borneSupRow, borneInfCol, borneSupCol := calculateBounds(ag.position, ag.width, ag.height, ag.orientation) + if !(borneInfCol < 0 || borneInfRow < 0 || borneSupRow > 20 || borneSupCol > 20) { + for i := borneInfRow; i < borneSupRow; i++ { + for j := borneInfCol; j < borneSupCol; j++ { + if !(j >= infCol && j < supCol && i >= infRow && i < supRow) && (env.station[i][j] != "B" && env.station[i][j] != "_" && env.station[i][j] != "W" && env.station[i][j] != "S") { + // Si on n'est pas sur une case atteignable, en dehors de la zone qu'occupe l'agent avant déplacement, on est bloqué + safe = false + } + } + } + if safe { + return true, or } } + } - return true + return false, agt.orientation + } func IsAgentBlocking(path []alg.Node, agt *Agent, env *Environment) bool { - // Détermine si un agent se trouve sur la case à visiter - + // Détermine si le movement est faisable if len(path) <= 0 { return false } - + // Calcul des bornes de position de l'agent avant mouvement + infRow, supRow, infCol, supCol := calculateBounds(agt.position, agt.width, agt.height, agt.orientation) // Simulation du déplacement ag := *agt ag.position = Coord{path[0].Row(), path[0].Col()} - rotateAgent(&ag, path[0].Or()) - - // Calcul des bornes de position de l'agent avant mouvement - infRow, supRow, infCol, supCol := calculateBounds(agt.position, agt.width, agt.height, agt.orientation) - - // Calcul des bornes de position de l'agent après mouvement - borneInfRow, borneSupRow, borneInfCol, borneSupCol := calculateBounds(ag.position, ag.width, ag.height, ag.orientation) - - for i := borneInfRow; i < borneSupRow; i++ { - for j := borneInfCol; j < borneSupCol; j++ { - if !(j >= infCol && j < supCol && i >= infRow && i < supRow) && env.station[i][j] == "A" { - // Si on est sur un agent, en dehors de la zone qu'occupe l'agent avant déplacement, on est bloqué - return true + for or := 0; or < 4; or++ { + rotateAgent(&ag, or) + blocking := false + + // Calcul des bornes de position de l'agent après mouvement + borneInfRow, borneSupRow, borneInfCol, borneSupCol := calculateBounds(ag.position, ag.width, ag.height, ag.orientation) + + if !(borneInfCol < 0 || borneInfRow < 0 || borneSupRow > 20 || borneSupCol > 20) { + for i := borneInfRow; i < borneSupRow; i++ { + for j := borneInfCol; j < borneSupCol; j++ { + if !(j >= infCol && j < supCol && i >= infRow && i < supRow) && env.station[i][j] == "A" { + + // Si on n'est pas sur une case atteignable, en dehors de la zone qu'occupe l'agent avant déplacement, on est bloqué + blocking = true + } + } + } + if !blocking { + // Si on n'a pas trouvé d'agent bloquant pour cette nouvelle position, on retourne faux + return false } } } - return false + // Le cas où dans tous les mouvements on est bloqué par un agent + return true } func (ag *Agent) isStuck() bool { @@ -175,39 +209,54 @@ func (ag *Agent) isStuck() bool { func (ag *Agent) MoveAgent() { - // ============ Initialisation des noeuds de départ ====================== - start := *alg.NewNode(ag.position[0], ag.position[1], 0, 0, ag.width, ag.height) - end := *alg.NewNode(ag.destination[0], ag.destination[1], 0, 0, ag.width, ag.height) // ================== Tentative de calcul du chemin ======================= - timea := time.Now() - path := alg.FindPath(ag.env.station, start, end, *alg.NewNode(-1, -1, 0, 0, 0, 0)) - fmt.Println(time.Since(timea)) + if len(ag.path) == 0 { + start, end := ag.generatePathExtremities() + // Recherche d'un chemin si inexistant + path := alg.FindPath(ag.env.station, start, end, *alg.NewNode(-1, -1, 0, 0, 0, 0), false) + ag.path = path + } // ================== Etude de faisabilité ======================= - // fmt.Println(ag.position,path[0]) - if IsAgentBlocking(path, ag, ag.env) { - // Si un agent bloque notre déplacement, on attend un temps aléatoire, et reconstruit un chemin en évitant la position + if IsAgentBlocking(ag.path, ag, ag.env) { + // TODO:voir comment gérer les situations de blocage + start, end := ag.generatePathExtremities() + // Si un agent bloque notre déplacement, on attend un temps aléatoire, et reconstruit time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond) - path = alg.FindPath(ag.env.station, start, end, path[0]) - time.Sleep(time.Second) + path := alg.FindPath(ag.env.station, start, end, *alg.NewNode(-1, -1, 0, 0, 0, 0), false) + ag.path = path + return } - if IsMovementSafe(path, ag, ag.env) { - removeAgent(&ag.env.station, ag) - rotateAgent(ag, path[0].Or()) + // ================== Déplacement si aucun problème ======================= + safe, or := IsMovementSafe(ag.path, ag, ag.env) + if safe { + RemoveAgent(&ag.env.station, ag) + rotateAgent(ag, or) //ag.env.station[ag.coordBasOccupation[0]][ag.coordBasOccupation[1]] = ag.isOn - ag.position[0] = path[0].Row() - ag.position[1] = path[0].Col() + ag.position[0] = ag.path[0].Row() + ag.position[1] = ag.path[0].Col() + if len(ag.path) > 1 { + ag.path = ag.path[1:] + } else { + ag.path = nil + } saveCells(&ag.env.station, ag.isOn, ag.position, ag.width, ag.height, ag.orientation) //ag.env.station[ag.coordBasOccupation[0]][ag.coordBasOccupation[1]] = "A" writeAgent(&ag.env.station, ag) // ============ Prise en compte de la vitesse de déplacement ====================== time.Sleep(ag.vitesse * time.Millisecond) - //fmt.Println(path[0]) - //fmt.Println(ag.position) + } +} +func (ag *Agent) generatePathExtremities() (alg.Node, alg.Node) { + // Génère les points extrêmes du chemin de l'agent + start := *alg.NewNode(ag.position[0], ag.position[1], 0, 0, ag.width, ag.height) + destination := ag.destination + end := *alg.NewNode(destination[0], destination[1], 0, 0, ag.width, ag.height) + return start, end } -func removeAgent(matrix *[20][20]string, agt *Agent) { +func RemoveAgent(matrix *[20][20]string, agt *Agent) { // Supprime l'agent de la matrice // Calcul des bornes de position de l'agent @@ -249,17 +298,24 @@ func saveCells(matrix *[20][20]string, savedCells map[Coord]string, position Coo func removeCoord(to_remove Coord, mapping map[Coord]string) { // Suppression d'une clé dans une map for coord, _ := range mapping { - if coord[0] == to_remove[0] && coord[1] == to_remove[1] { + if equalCoord(&coord, &to_remove) { delete(mapping, coord) } } } +func equalCoord(coord1, coord2 *Coord) bool { + // Vérifie l'égalité de 2 objets Coord + return coord1[0] == coord2[0] && coord1[1] == coord2[1] +} + +// Fonction utilitaire de rotation func rotateAgent(agt *Agent, orientation int) { agt.orientation = orientation } func calculateBounds(position Coord, width, height, orientation int) (infRow, supRow, infCol, supCol int) { + // Fonction de génération des frontières d'un objet ayant une largeur et une hauteur, en focntion de son orientation borneInfRow := 0 borneSupRow := 0 borneInfCol := 0 @@ -268,21 +324,25 @@ func calculateBounds(position Coord, width, height, orientation int) (infRow, su // Calcul des bornes de position de l'agent après mouvement switch orientation { case 0: + // Orienté vers le haut borneInfRow = position[0] - width + 1 borneSupRow = position[0] + 1 borneInfCol = position[1] borneSupCol = position[1] + height case 1: + // Orienté vers la droite borneInfRow = position[0] borneSupRow = position[0] + height borneInfCol = position[1] borneSupCol = position[1] + width case 2: + // Orienté vers le bas borneInfRow = position[0] borneSupRow = position[0] + width borneInfCol = position[1] borneSupCol = position[1] + height case 3: + // Orienté vers la gauche borneInfRow = position[0] borneSupRow = position[0] + height borneInfCol = position[1] - width + 1 diff --git a/internal/simulation/env.go b/internal/simulation/env.go index 107b44e75fd80e8d4fb2d8c8880ba34a6b58b5c6..9ecf0fb640bbe1ca95ed42286e342e95b21af82b 100644 --- a/internal/simulation/env.go +++ b/internal/simulation/env.go @@ -11,8 +11,12 @@ type Environment struct { agentCount int station [20][20]string agentsChan map[AgentID]chan AgentID + // zones map[Coord]ZoneID // Zones de la station + // panneaux map[ZoneID][]alg.Node // Les panneaux de la station, permettant d'aller vers la zone } +type ZoneID int + func NewEnvironment(ags []Agent, carte [20][20]string, agentsCh map[AgentID]chan AgentID) (env *Environment) { return &Environment{ags: ags, agentCount: len(ags), station: carte, agentsChan: agentsCh} } @@ -22,6 +26,18 @@ func (env *Environment) AddAgent(agt Agent) { env.agentCount++ } +func (env *Environment) RemoveAgent(agt Agent) { + for i := 0; i < len(env.station); i++ { + if env.ags[i].id == agt.id{ + // Utiliser la syntaxe de découpage pour supprimer l'élément + env.ags = append(env.ags[:i], env.ags[i+1:]...) + // Sortir de la boucle après avoir trouvé et supprimé l'élément + break + } + } + env.agentCount-- +} + func (env *Environment) Do(a Action, c Coord) (err error) { env.Lock() defer env.Unlock() diff --git a/internal/simulation/simu.go b/internal/simulation/simu.go index 52a019e6ec63a23de4071078ec59b94bbbd12010..155b59124f92c4b642d57677294c1ebf99bd02e6 100644 --- a/internal/simulation/simu.go +++ b/internal/simulation/simu.go @@ -3,8 +3,6 @@ package simulation import ( "fmt" "log" - - //"math/rand" "sync" "time" ) @@ -42,6 +40,7 @@ var carte [20][20]string = [20][20]string{ {"X", "X", "X", "X", "S", "S", "X", "X", "X", "X", "X", "X", "E", "E", "X", "X", "X", "X", "X", "X"}, } + var playground [20][20]string = [20][20]string{ {"_", "X", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_"}, {"_", "X", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_"}, @@ -97,8 +96,15 @@ func NewSimulation(agentCount int, maxStep int, maxDuration time.Duration) (simu syncChan := make(chan int) //ag := NewAgent(id, &simu.env, syncChan, time.Duration(time.Second), 0, true, Coord{0, 8 + i%2}, Coord{0, 8 + i%2}, &UsagerLambda{}, Coord{0, 8 + i%2}, Coord{12 - 4*(i%2), 18 - 15*(i%2)}) - ag := NewAgent(id, &simu.env, syncChan, 1000, 0, true, &UsagerLambda{}, Coord{2, 8}, Coord{13, 15}, 2, 1) - //ag := NewAgent(id, &simu.env, syncChan, 1000, 0, true, &UsagerLambda{}, Coord{5, 8}, Coord{0, 0}, 2, 1) + //ag := NewAgent(id, &simu.env, syncChan, 1000, 0, true, &UsagerLambda{}, Coord{3, 4}, Coord{18, 12}, 2, 1) + ag := &Agent{} + if i%2==0{ + ag = NewAgent(id, &simu.env, syncChan, 1000, 0, true, &UsagerLambda{}, Coord{18, 4}, Coord{0, 8}, 2, 1) + }else{ + ag = NewAgent(id, &simu.env, syncChan, 1000, 0, true, &UsagerLambda{}, Coord{1, 8}, Coord{8, 5}, 1, 1) + } + + //ag := NewAgent(id, &simu.env, syncChan, 1000, 0, true, &UsagerLambda{}, Coord{1, 17}, Coord{0, 0}, 2, 1) // ajout de l'agent à la simulation simu.agents = append(simu.agents, *ag) diff --git a/internal/simulation/usagerLambda.go b/internal/simulation/usagerLambda.go index 843be3742b32ab72bbfaef92a5696af2d4cb08ec..abe11892a9c5fab8b36093dd823940647a0f06e6 100644 --- a/internal/simulation/usagerLambda.go +++ b/internal/simulation/usagerLambda.go @@ -1,6 +1,7 @@ package simulation import ( + "fmt" "math/rand" "time" ) @@ -17,7 +18,10 @@ func (ul *UsagerLambda) Percept(ag *Agent) { } func (ul *UsagerLambda) Deliberate(ag *Agent) { - if ag.stuck { + if ag.position == ag.destination && (ag.isOn[ag.position] == "W" || ag.isOn[ag.position] == "S") { + fmt.Println(ag.id, "disapear") + ag.decision = Disapear + } else if ag.stuck { ag.decision = Wait } else { ag.decision = Move @@ -30,6 +34,8 @@ func (ul *UsagerLambda) Act(ag *Agent) { } else if ag.decision == Wait { n := rand.Intn(2) // temps d'attente aléatoire time.Sleep(time.Duration(n) * time.Second) + } else if ag.decision == Disapear { + RemoveAgent(&ag.env.station, ag) } }