diff --git a/cmd/simu/main.go b/cmd/simu/main.go index 9127258c9d064186e80c3cd37ba03c22ea0cc76b..a4c765ec763cea6fa19babf9d257506f54cc92ca 100644 --- a/cmd/simu/main.go +++ b/cmd/simu/main.go @@ -10,7 +10,7 @@ import ( ) func main() { - s := simulation.NewSimulation(1, -1, 600*time.Second) + s := simulation.NewSimulation(6, -1, 600*time.Second) //go simulation.StartAPI(s) go func() { for { diff --git a/internal/simulation/agent.go b/internal/simulation/agent.go index db5e60b13c91cba6a52a41a12e545af09f2f4378..a78c1f1d18f3fd2ef72a87c7bad672b7b8004637 100644 --- a/internal/simulation/agent.go +++ b/internal/simulation/agent.go @@ -11,10 +11,8 @@ import ( //"log" "math/rand" - "math" alg "metrosim/internal/algorithms" "time" - "sort" ) type Action int64 @@ -570,88 +568,7 @@ func (ag *Agent) findNearestExit() (alg.Coord){ return nearest } -func (ag *Agent) findNearestGates(gates []alg.Coord) []Gate { - var gateDistances []Gate - // Calcul de la distance pour chaque porte - for _, gate := range gates { - dist := alg.Abs(ag.position[0]-gate[0]) + alg.Abs(ag.position[1]-gate[1]) - gateDistances = append(gateDistances, Gate{Position: gate, Distance: float64(dist)}) - } - - // Tri des Coords par distance - sort.Slice(gateDistances, func(i, j int) bool { - return gateDistances[i].Distance < gateDistances[j].Distance - }) - - return gateDistances -} - -// Normalise les valeurs d'un ensemble de portes -func normalizeGates(gates []Gate) ([]Gate, float64, float64) { - var minAgents, maxAgents float64 = math.MaxFloat64, 0 - var minDistance, maxDistance float64 = math.MaxFloat64, 0 - - // Trouver les valeurs max et min pour la normalisation - for _, gate := range gates { - if gate.NbAgents > maxAgents { - maxAgents = gate.NbAgents - } - if gate.NbAgents < minAgents { - minAgents = gate.NbAgents - } - if gate.Distance > maxDistance { - maxDistance = gate.Distance - } - if gate.Distance < minDistance { - minDistance = gate.Distance - } - } - - // Normaliser les valeurs - d_agt := (maxAgents - minAgents) - if d_agt == 0 { - d_agt = 1.0 - } - d_dist := (maxDistance - minDistance) - if d_dist == 0 { - d_dist = 1.0 - } - fmt.Println("[normalizeGates] d_dist : ",d_dist) - for i := range gates { - gates[i].NbAgents = (gates[i].NbAgents - minAgents) / d_agt - //fmt.Println("[normalizeGates] gates[i].Distance : ",gates[i].Distance) - //fmt.Println("[normalizeGates] minDistance : ",minDistance) - //fmt.Println("[normalizeGates] d_dist : ",d_dist) - gates[i].Distance = (gates[i].Distance - minDistance) / d_dist - } - return gates, float64(maxAgents - minAgents), maxDistance - minDistance -} - - - -func (ag *Agent) findBestGate(gates []alg.Coord) alg.Coord { - gatesDistances := make([]Gate, len(gates)) - for i, gate := range gates { - dist := alg.Abs(ag.position[0]-gate[0]) + alg.Abs(ag.position[1]-gate[1]) - nbAgents := float64(ag.env.getNbAgentsAround(gate)) - gatesDistances[i] = Gate{Position: gate, Distance: float64(dist), NbAgents: nbAgents} - } - fmt.Println("[findBestGate] gates non normalisé : ",gatesDistances) - normalizedGates, _, _ := normalizeGates(gatesDistances) - fmt.Println("[findBestGate] gates normalisé : ",normalizedGates) - var bestGate Gate - lowestScore := 2.0 // Puisque la somme des scores normalisés ne peut pas dépasser 2 - - for _, gate := range normalizedGates { - score := float64(gate.NbAgents) + gate.Distance - if score < lowestScore { - lowestScore = score - bestGate = gate - } - } - return bestGate.Position -} func findMetro(env *Environment, gateToFind *alg.Coord) *Metro { diff --git a/internal/simulation/controleur.go b/internal/simulation/controleur.go index 4fdb61e6b72e2717e1c72d53e0f7f2e2a36ad6e0..0085ac0ff9a20275cb112db8be453b9a65c49dad 100644 --- a/internal/simulation/controleur.go +++ b/internal/simulation/controleur.go @@ -1,6 +1,10 @@ package simulation -//ajouter liste des agents déjà controllés +/* + Le controleur se déplace aléatoirement dans la station pendant un certain temps + et controle les agents qui se trouvent devant lui si ils ne sont pas déjà controllés par un autre controleur, + si l'agent est un fraudeur alors il est expulsé, sinon il est arreté pendant un certain temps +*/ import ( "fmt" @@ -10,13 +14,6 @@ import ( alg "metrosim/internal/algorithms" ) -/* - Je suppose que l'id du controleur est de format "Cont + un chiffre" - Exemple : "Cont1" - et l'id du l'agent est de format "Agent + un chiffre" - Exemple : "Agent1" -*/ - type Controleur struct { req *Request // requete reçue par le controleur faceCase string // chaine de caractère qui contient l'id de l'agent qui se trouve devant le controleur, exemple : "Agent1", "Fraudeur1", "X" ,etc. @@ -24,14 +21,12 @@ type Controleur struct { isExpired bool // true si le controleur est expiré, false sinon } - - func (c *Controleur) Percept(ag *Agent) { //initialiser le faceCase en fonction de la direction de l'agent c.faceCase = ag.getFaceCase() switch { // comportement par défaut (comportement agent Lambda) - case ag.request != nil: //verifier si l'agent est communiqué par un autre agent (A VOIR SI IL EXISTE DEJA UN AGENT QUI COMMUNIQUE AVEC LE CONTROLEUR) + case ag.request != nil: //verifier si l'agent est communiqué par un autre agent //print("Requete recue par l'agent lambda : ", ag.request.decision, "\n") c.req = ag.request default: @@ -46,29 +41,29 @@ func (c *Controleur) Percept(ag *Agent) { func (c *Controleur) Deliberate(ag *Agent) { // Verifier si la case devant lui contient un agent ou un fraudeur // Créer l'expression régulière - regexAgent := `^Agent\d+$` // \d+ correspond à un ou plusieurs chiffres + //regexAgent := `^Agent\d+$` // \d+ correspond à un ou plusieurs chiffres regexFraudeur := `^Fraudeur\d+$` + existAgt := existAgent(c.faceCase) // true si l'agent existe dans la case en face , false sinon // Vérifier si la valeur de faceCase ne correspond pas au motif - matchedAgt, err1 := regexp.MatchString(regexAgent, c.faceCase) - matchedFraud, err2 := regexp.MatchString(regexFraudeur, c.faceCase) + //matchedAgt, err1 := regexp.MatchString(regexAgent, c.faceCase) + matchedFraud, err := regexp.MatchString(regexFraudeur, c.faceCase) //fmt.Println("faceCase : ", c.faceCase) //fmt.Println("matchedAgt : ", matchedAgt) - if err1 != nil || err2 != nil { - fmt.Println("Erreur lors de l'analyse de la regex :", err1, err2) + if err!= nil { + fmt.Println("Erreur lors de l'analyse de la regex :",err) return } else { - if matchedAgt && ag.env.controlledAgents[AgentID(c.faceCase)] == false { // si l'agent devant le controleur est un agent et qu'il n'a pas encore été controlé - //fmt.Println("L'agent ", c.face, " a été détecté par le controleur") - ag.decision = Stop // arreter l'agent devant lui - } else if matchedFraud && !ag.env.controlledAgents[AgentID(c.faceCase)] { + if matchedFraud && !ag.env.controlledAgents[AgentID(c.faceCase)] { ag.decision = Expel // virer l'agent devant lui - //sinon comportement par défaut (comportement de l'usager lambda) - }else if ag.position == ag.destination && (ag.isOn[ag.position] == "W" || ag.isOn[ag.position] == "S") { // si l'agent est arrivé à sa destination et qu'il est sur une sortie + }else if existAgt && !ag.env.controlledAgents[AgentID(c.faceCase)] { // si l'agent devant le controleur est un agent et qu'il n'a pas encore été controlé + //fmt.Println("L'agent ", c.face, " a été détecté par le controleur") + ag.decision = Stop // arreter l'agent + }else if ag.position == ag.destination && (ag.isOn[ag.position] == "W" || ag.isOn[ag.position] == "S") { // si le controleur est arrivé à sa destination et qu'il est sur une sortie //fmt.Println(ag.id, "disappear") ag.decision = Disappear - } else if ag.stuck{ // si l'agent est bloqué + } else if ag.stuck{ // si le controleur est bloqué ag.decision = Wait }else { ag.decision = Move @@ -97,7 +92,7 @@ func (c *Controleur) Act(ag *Agent) { case Disappear: RemoveAgent(&ag.env.station, ag) - default : //Expel ou Wait + case Expel, Stop : //Expel ou Stop agt_face_id := AgentID(c.faceCase) //id de l'agent qui se trouve devant le controleur //fmt.Print("L'agent ", agt_face_id, " a été expulsé\n") ag.env.agentsChan[agt_face_id] <- *NewRequest(ag.env.agentsChan[ag.id], ag.decision) // envoie la decision du controleur à l'agent qui se trouve devant lui @@ -106,11 +101,11 @@ func (c *Controleur) Act(ag *Agent) { func (c *Controleur) randomDestination(ag *Agent) alg.Coord { rand.Seed(time.Now().UnixNano()) // le générateur de nombres aléatoires - randomRow := rand.Intn(20) // Génère un entier aléatoire entre 0 et 19 - randomCol := rand.Intn(20) // Génère un entier aléatoire entre 0 et 19 + randomRow := rand.Intn(len(ag.env.station[0])) // Génère un entier aléatoire entre 0 et 19 + randomCol := rand.Intn(len(ag.env.station[1])) // Génère un entier aléatoire entre 0 et 19 for ag.env.station[randomRow][randomCol] != "_" { - randomRow = rand.Intn(20) // Génère un entier aléatoire entre 0 et 19 - randomCol = rand.Intn(20) // Génère un entier aléatoire entre 0 et 19 + randomRow = rand.Intn(len(ag.env.station[0])) // Génère un entier aléatoire entre 0 et 19 + randomCol = rand.Intn(len(ag.env.station[1])) // Génère un entier aléatoire entre 0 et 19 } return alg.Coord{randomRow, randomCol} } diff --git a/internal/simulation/metro.go b/internal/simulation/metro.go index 3b30ac3daf0ec6a5aa8c253ef1e085981ee3264c..4130bffd523adc9c61e99cd698cf301b7973ca27 100644 --- a/internal/simulation/metro.go +++ b/internal/simulation/metro.go @@ -47,7 +47,7 @@ func (metro *Metro) Start() { metro.printMetro() } if refTime.Add(metro.frequency).Before(time.Now()) { - metro.dropUsers() + //metro.dropUsers() metro.way.openGates() metro.pickUpUsers() metro.way.closeGates() diff --git a/internal/simulation/mobiliteReduite.go b/internal/simulation/mobiliteReduite.go index 75a90231ffbd706971429dfe2972b78b4139b33e..0da37a4f1499aac008e5b2d31e5ac6976d7ef112 100644 --- a/internal/simulation/mobiliteReduite.go +++ b/internal/simulation/mobiliteReduite.go @@ -1,4 +1,7 @@ package simulation +/* + L'agent à Mobilité Reduite cherche la porte du metro la plus proche de lui +*/ import ( "fmt" @@ -6,6 +9,7 @@ import ( "math/rand" "time" alg "metrosim/internal/algorithms" + "sort" ) @@ -16,7 +20,7 @@ type MobiliteReduite struct { func (mr *MobiliteReduite) Percept(ag *Agent) { - mr.once.Do(func(){mr.setUpDestination(ag)}) // la fonction setUp est executé à la premiere appel de la fonction Percept() + mr.once.Do(func(){mr.setUpDestination(ag)}) // la fonction setUp est executé à la premiere appel à la fonction Percept() switch { case ag.request != nil: //verifier si l'agent est communiqué par un autre agent, par exemple un controleur lui a demandé de s'arreter fmt.Printf("Requete recue par l'agent mR : %d \n", ag.request.decision) @@ -101,7 +105,24 @@ func (mr *MobiliteReduite) Act(ag *Agent) { */ func (mr *MobiliteReduite)setUpDestination(ag *Agent){ choix_voie := rand.Intn(2) // choix de la voie de métro aléatoire - dest_porte := (ag.findNearestGates(ag.env.metros[choix_voie].way.gates)) + dest_porte := (mr.findNearestGates(ag, ag.env.metros[choix_voie].way.gates)) //fmt.Println("[MobiliteReduite, setUpDestination] dest_porte = ",dest_porte) ag.destination = dest_porte[0].Position } + + +func (mr *MobiliteReduite) findNearestGates(ag *Agent, gates []alg.Coord) []Gate { + var gateDistances []Gate + // Calcul de la distance pour chaque porte + for _, gate := range gates { + dist := alg.Abs(ag.position[0]-gate[0]) + alg.Abs(ag.position[1]-gate[1]) + gateDistances = append(gateDistances, Gate{Position: gate, Distance: float64(dist)}) + } + + // Tri des Coords par distance + sort.Slice(gateDistances, func(i, j int) bool { + return gateDistances[i].Distance < gateDistances[j].Distance + }) + + return gateDistances +} \ No newline at end of file diff --git a/internal/simulation/simu.go b/internal/simulation/simu.go index 2bf9704e7c86c409fa5089b4a80acc1053ed2103..1855a48c7fc970db0d4f1b44bd7e80657ad3e849 100644 --- a/internal/simulation/simu.go +++ b/internal/simulation/simu.go @@ -140,17 +140,25 @@ func NewSimulation(agentCount int, maxStep int, maxDuration time.Duration) (simu // création de l'agent syncChan := make(chan int) + ag := &Agent{} //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{18, 4}, Coord{0, 8}, 2, 1) //ag := &Agent{} - + /* id := fmt.Sprintf("Agent%d", i) ag := NewAgent(id, &simu.env, syncChan, 400, 0, true, &UsagerLambda{}, alg.Coord{0, 28}, alg.Coord{8, 5}, 1, 1) + */ + + id := fmt.Sprintf("Cont%d", i) + //NewAgent(id string, env *Environment, syncChan chan int, vitesse time.Duration, force int, politesse bool, behavior Behavior, departure, destination Coord, width, height int) + ag = NewAgent(id, &simu.env, syncChan, 200, 0, true, &Controleur{}, alg.Coord{0, 28}, alg.Coord{0, 9}, 1, 1) + /* + if i%2 == 0 { //Type Agent - id := fmt.Sprintf("MR%d", i) + id := fmt.Sprintf("Cont%d", i) //NewAgent(id string, env *Environment, syncChan chan int, vitesse time.Duration, force int, politesse bool, behavior Behavior, departure, destination Coord, width, height int) - ag = NewAgent(id, &simu.env, syncChan, 200, 0, true, &UsagerLambda{}, alg.Coord{49, 32}, alg.Coord{0, 9}, 2, 1) + ag = NewAgent(id, &simu.env, syncChan, 200, 0, true, &Controleur{}, alg.Coord{0, 28}, alg.Coord{0, 9}, 2, 1) } else { // Type Controleur //id := fmt.Sprintf("Controleur%d", i) id := fmt.Sprintf("Agent%d", i) @@ -256,11 +264,13 @@ func (simu *Simulation) Print() { for i := 0; i < 20; i++ { for j := 0; j < 50; j++ { element := simu.env.station[i][j] + if len(element) > 1 { - fmt.Print(element[len(element)-1:] + " ") // Afficher le premier caractère si la longueur est supérieure à 1 - } else { - fmt.Print(element + " ") - } + //fmt.Print(element[len(element)-1:] + " ") // Afficher le premier caractère si la longueur est supérieure à 1 + fmt.Print(element[0:1] + " ") + } else { + fmt.Print(element + " ") + } } fmt.Println() } diff --git a/internal/simulation/usagerLambda.go b/internal/simulation/usagerLambda.go index dccadee1b27f2a3fad625f9ea94779ca9e64f181..cea92ebdb940cbb9df94e267a1a4fe6a938fc8d0 100644 --- a/internal/simulation/usagerLambda.go +++ b/internal/simulation/usagerLambda.go @@ -15,7 +15,7 @@ type UsagerLambda struct { } func (ul *UsagerLambda) Percept(ag *Agent) { - ul.once.Do(func(){ul.setUpDestination(ag)}) // la fonction setUp est executé à la premiere appel de la fonction Percept() + //ul.once.Do(func(){ul.setUpDestination(ag)}) // la fonction setUp est executé à la premiere appel de la fonction Percept() switch { case ag.request != nil: //verifier si l'agent est communiqué par un autre agent, par exemple un controleur lui a demandé de s'arreter //print("Requete recue par l'agent lambda : ", ag.request.decision, "\n") @@ -84,9 +84,3 @@ func (ul *UsagerLambda) Act(ag *Agent) { } } - -func (ul *UsagerLambda)setUpDestination(ag *Agent){ - choix_voie := rand.Intn(2) // choix de la voie de métro aléatoire - dest_porte := (ag.findBestGate(ag.env.metros[choix_voie].way.gates)) - ag.destination = dest_porte -} \ No newline at end of file diff --git a/internal/simulation/usagerNormal.go b/internal/simulation/usagerNormal.go new file mode 100644 index 0000000000000000000000000000000000000000..0458e54240129df7a7b9de12cd8cccd3e3e96efa --- /dev/null +++ b/internal/simulation/usagerNormal.go @@ -0,0 +1,165 @@ +package simulation + + +/* + Agent qui se dirige vers la porte la plus proche sans trop de monde (bon rapport monde/proximité ) +*/ + +import ( + "fmt" + + "math/rand" + alg "metrosim/internal/algorithms" + "time" + "sync" + "math" +) + +type UsagerNormal struct { + req *Request // requete recue par l'agent lambda + once sync.Once +} + +func (ul *UsagerNormal) Percept(ag *Agent) { + ul.once.Do(func(){ul.setUpDestination(ag)}) // la fonction setUp est executé à la premiere appel de la fonction Percept() + switch { + case ag.request != nil: //verifier si l'agent est communiqué par un autre agent, par exemple un controleur lui a demandé de s'arreter + //print("Requete recue par l'agent lambda : ", ag.request.decision, "\n") + ul.req = ag.request + default: + ag.stuck = ag.isStuck() + if ag.stuck { + return + + } + } +} + +func (ul *UsagerNormal) Deliberate(ag *Agent) { + //fmt.Println("[AgentLambda Deliberate] decision :", ul.req.decision) + if (ul.req != nil ) { + if ul.req.decision == Stop{ + ag.decision = Wait + ul.req = nil //demande traitée + return + } else if ul.req.decision == Expel { // cette condition est inutile car l'usager lambda ne peut pas etre expulsé , elle est nécessaire pour les agents fraudeurs + //fmt.Println("[AgentLambda, Deliberate] Expel") + ag.decision = Expel + ul.req = nil //demande traitée + return + }else if ul.req.decision == Disappear { + ag.decision = Disappear + return + }else if ul.req.decision == Wait { + ag.decision = Wait + }else if ul.req.decision == EnterMetro { + ag.decision = EnterMetro + } + }else if (ag.position != ag.departure && ag.position == ag.destination) && (ag.isOn[ag.position] == "W" || ag.isOn[ag.position] == "S") { // si l'agent est arrivé à sa destination et qu'il est sur une sortie + //fmt.Println(ag.id, "disappear") + ag.decision = Disappear + } else if ag.stuck{ // si l'agent est bloqué + ag.decision = Wait + }else { + ag.decision = Move + } +} + +func (ul *UsagerNormal) Act(ag *Agent) { + //fmt.Println("[AgentLambda Act] decision :",ag.decision) + if ag.decision == Move { + ag.MoveAgent() + } 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 == Disappear { + RemoveAgent(&ag.env.station, ag) + } else if ag.decision == EnterMetro { + fmt.Println("[UsagerNormal, Act] EnterMetro") + RemoveAgent(&ag.env.station, ag) + ul.req.demandeur <- *NewRequest(ag.env.agentsChan[ag.id], ACK) + } else if ag.decision == Expel { + //fmt.Println("[AgentLambda, Act] Expel") + ag.destination = ag.findNearestExit() + //fmt.Println("[AgentLambda, Act] destination = ",ag.destination) + ag.env.controlledAgents[ag.id] = true + ag.path = make([]alg.Node, 0) + ag.MoveAgent() + } else { + // nothing to do + } +} + + +func (ul *UsagerNormal)setUpDestination(ag *Agent){ + choix_voie := rand.Intn(2) // choix de la voie de métro aléatoire + dest_porte := (ul.findBestGate(ag, ag.env.metros[choix_voie].way.gates)) + ag.destination = dest_porte +} + + + +func (ul *UsagerNormal) findBestGate(ag *Agent, gates []alg.Coord) alg.Coord { + gatesDistances := make([]Gate, len(gates)) + for i, gate := range gates { + dist := alg.Abs(ag.position[0]-gate[0]) + alg.Abs(ag.position[1]-gate[1]) + nbAgents := float64(ag.env.getNbAgentsAround(gate)) + gatesDistances[i] = Gate{Position: gate, Distance: float64(dist), NbAgents: nbAgents} + } + fmt.Println("[findBestGate] gates non normalisé : ",gatesDistances) + normalizedGates, _, _ := normalizeGates(gatesDistances) + fmt.Println("[findBestGate] gates normalisé : ",normalizedGates) + var bestGate Gate + lowestScore := 2.0 // Puisque la somme des scores normalisés ne peut pas dépasser 2 + + for _, gate := range normalizedGates { + score := float64(gate.NbAgents) + gate.Distance + if score < lowestScore { + lowestScore = score + bestGate = gate + } + } + return bestGate.Position +} + + +// Normalise les valeurs d'un ensemble de portes +func normalizeGates(gates []Gate) ([]Gate, float64, float64) { + var minAgents, maxAgents float64 = math.MaxFloat64, 0 + var minDistance, maxDistance float64 = math.MaxFloat64, 0 + + // Trouver les valeurs max et min pour la normalisation + for _, gate := range gates { + if gate.NbAgents > maxAgents { + maxAgents = gate.NbAgents + } + if gate.NbAgents < minAgents { + minAgents = gate.NbAgents + } + if gate.Distance > maxDistance { + maxDistance = gate.Distance + } + if gate.Distance < minDistance { + minDistance = gate.Distance + } + } + + // Normaliser les valeurs + d_agt := (maxAgents - minAgents) + if d_agt == 0 { + d_agt = 1.0 + } + d_dist := (maxDistance - minDistance) + if d_dist == 0 { + d_dist = 1.0 + } + fmt.Println("[normalizeGates] d_dist : ",d_dist) + for i := range gates { + gates[i].NbAgents = (gates[i].NbAgents - minAgents) / d_agt + //fmt.Println("[normalizeGates] gates[i].Distance : ",gates[i].Distance) + //fmt.Println("[normalizeGates] minDistance : ",minDistance) + //fmt.Println("[normalizeGates] d_dist : ",d_dist) + gates[i].Distance = (gates[i].Distance - minDistance) / d_dist + } + return gates, float64(maxAgents - minAgents), maxDistance - minDistance +}