From 7cfe3f6dcf66750e40d213710650b73f461263f8 Mon Sep 17 00:00:00 2001
From: jrafei <jana.eltayeb-el-rafei@etu.utc.fr>
Date: Tue, 12 Dec 2023 20:35:23 +0100
Subject: [PATCH] first_modifs

---
 cmd/test/main.go                    | 26 ++++++++++
 internal/simulation/agent.go        | 18 +++++--
 internal/simulation/controleur.go   | 77 +++++++++++++++++++++++++++++
 internal/simulation/env.go          | 13 ++++-
 internal/simulation/simu.go         |  8 ++-
 internal/simulation/usagerLambda.go | 40 ++++++++++++---
 6 files changed, 168 insertions(+), 14 deletions(-)
 create mode 100644 cmd/test/main.go
 create mode 100644 internal/simulation/controleur.go

diff --git a/cmd/test/main.go b/cmd/test/main.go
new file mode 100644
index 0000000..f5e5e2d
--- /dev/null
+++ b/cmd/test/main.go
@@ -0,0 +1,26 @@
+package main
+
+import (
+	"fmt"
+	"regexp"
+)
+
+func main() {
+	faceCase := "Agent1000" // Remplacez ceci par votre variable
+
+	// Créer l'expression régulière
+	regexPattern := `^Agent\d+$` // \d+ correspond à un ou plusieurs chiffres
+	matched, err := regexp.MatchString(regexPattern, faceCase)
+
+	if err != nil {
+		fmt.Println("Erreur lors de l'analyse de la regex :", err)
+		return
+	}
+
+	// Vérifiez si la chaîne ne correspond pas au motif
+	if !matched {
+		fmt.Println("La chaîne ne correspond pas au motif 'Agentx'")
+	} else {
+		fmt.Println("La chaîne correspond au motif 'Agentx'")
+	}
+}
diff --git a/internal/simulation/agent.go b/internal/simulation/agent.go
index 5013677..b775130 100644
--- a/internal/simulation/agent.go
+++ b/internal/simulation/agent.go
@@ -24,6 +24,7 @@ const (
 	Mark
 	Wait
 	Move
+	Expel // decision du Controleur
 )
 
 type Coord [2]int
@@ -45,19 +46,30 @@ type Agent struct {
 	stuck       bool
 	width       int
 	height      int
-	orientation int
+	orientation int //0 : vers le haut, 1 : vers la droite, 2 : vers le bas, 3 : vers la gauche
+	request     *Request
 }
 
+type Request struct {
+	demandeur AgentID
+	decision int
+}
+
+
 type Behavior interface {
 	Percept(*Agent)
 	Deliberate(*Agent)
 	Act(*Agent)
 }
 
+func NewRequest(demandeur AgentID, decision int) (req *Request) {
+	return &Request{demandeur, decision}
+}
+
 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}
+	return &Agent{AgentID(id), vitesse, force, politesse, departure, departure, destination, behavior, env, syncChan, Noop, isOn, false, width, height, 0, nil}
 }
 
 func (ag *Agent) ID() AgentID {
@@ -229,7 +241,7 @@ func writeAgent(matrix *[20][20]string, agt *Agent) {
 
 	for i := borneInfRow; i < borneSupRow; i++ {
 		for j := borneInfCol; j < borneSupCol; j++ {
-			matrix[i][j] = "A"
+			matrix[i][j] = string(agt.id)
 		}
 	}
 
diff --git a/internal/simulation/controleur.go b/internal/simulation/controleur.go
new file mode 100644
index 0000000..b7e3ea0
--- /dev/null
+++ b/internal/simulation/controleur.go
@@ -0,0 +1,77 @@
+package simulation
+
+import (
+	"math/rand"
+	"time"
+	"regexp"
+	"fmt"
+)
+
+
+/*
+	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{
+	faceCase string // chaine de caractère qui contient l'id de l'agent qui se trouve devant le controleur, exemple : "Agent1", "Fraudeur1", "X" ,etc.
+}
+
+func (c *Controleur) Percept(ag *Agent) {
+	env := ag.env
+
+	if ag.orientation == 0 { // vers le haut
+		c.faceCase = env.station[ag.position[0]-1][ag.position[1]]
+	} else if ag.orientation == 1 { // vers la droite
+		c.faceCase = env.station[ag.position[0]][ag.position[1]+1]
+	} else if ag.orientation == 2 { // vers le bas
+		c.faceCase = env.station[ag.position[0]+1][ag.position[1]]
+	} else { // vers la gauche
+		c.faceCase = env.station[ag.position[0]][ag.position[1]-1]
+	}
+
+}
+
+ 
+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
+	regexFraudeur := `^Fraudeur\d+$`
+	
+	// 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)
+
+	if err1 != nil || err2 != nil {
+		fmt.Println("Erreur lors de l'analyse de la regex :", err1, err2)
+		return
+	} else {
+		if matchedAgt {
+			ag.decision = Wait // arreter l'agent devant lui
+		} else if matchedFraud {
+			ag.decision = Expel // virer l'agent devant lui
+		} else{
+			// Comportement de l'usager lambda (par defaut)
+			if ag.stuck {
+				ag.decision = Wait
+			} else {
+				ag.decision = Move
+			}
+		}
+	}
+}
+
+func (c *Controleur) Act(ag *Agent) {
+	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 {
+		agt_face_id := AgentID(c.faceCase)
+		ag.env.agentsChan[agt_face_id] <- *NewRequest(ag.id, ag.decision) // envoie la decision du controleur à l'agent qui se trouve devant lui
+	}
+}
diff --git a/internal/simulation/env.go b/internal/simulation/env.go
index 107b44e..5ed6c4b 100644
--- a/internal/simulation/env.go
+++ b/internal/simulation/env.go
@@ -10,13 +10,17 @@ type Environment struct {
 	ags        []Agent
 	agentCount int
 	station    [20][20]string
-	agentsChan map[AgentID]chan AgentID
+	agentsChan map[AgentID]chan Request
 }
 
-func NewEnvironment(ags []Agent, carte [20][20]string, agentsCh map[AgentID]chan AgentID) (env *Environment) {
+
+
+
+func NewEnvironment(ags []Agent, carte [20][20]string, agentsCh map[AgentID]chan Request) (env *Environment) {
 	return &Environment{ags: ags, agentCount: len(ags), station: carte, agentsChan: agentsCh}
 }
 
+
 func (env *Environment) AddAgent(agt Agent) {
 	env.ags = append(env.ags, agt)
 	env.agentCount++
@@ -51,3 +55,8 @@ func (env *Environment) PI() float64 {
 func (env *Environment) Rect() Coord {
 	return Coord{0, 0}
 }
+
+
+func (env *Environment) GetAgentChan(agt_id AgentID) chan Request {
+	return env.agentsChan[agt_id]
+}
\ No newline at end of file
diff --git a/internal/simulation/simu.go b/internal/simulation/simu.go
index 52a019e..04b7e22 100644
--- a/internal/simulation/simu.go
+++ b/internal/simulation/simu.go
@@ -18,6 +18,7 @@ import (
  * Q : Voie
  * _ : Couloir, case libre
  * B: Bridge/Pont, zone accessible
+ * valeur de AgentID : Agent
  */
 var carte [20][20]string = [20][20]string{
 	{"X", "X", "X", "X", "X", "X", "X", "X", "W", "W", "X", "X", "X", "X", "X", "X", "X", "X", "X", "X"},
@@ -110,13 +111,14 @@ func NewSimulation(agentCount int, maxStep int, maxDuration time.Duration) (simu
 		ag.env.AddAgent(*ag)
 
 		// ajout
-		simu.env.agentsChan[ag.id] = make(chan AgentID)
+		simu.env.agentsChan[ag.id] = make(chan Requete)
 	}
 
 	return simu
 }
 
 func (simu *Simulation) Run() {
+	// A REVOIR si nécessaire de faire appeler simu.env.pi() 
 	log.Printf("Démarrage de la simulation [step: %d, π: %f]", simu.step, simu.env.PI())
 
 	// Démarrage du micro-service de Log
@@ -145,7 +147,7 @@ func (simu *Simulation) Run() {
 			step := 0
 			for {
 				step++
-				c, _ := simu.syncChans.Load(agt.ID())
+				c, _ := simu.syncChans.Load(agt.ID()) // communiquer les steps aux agents
 				c.(chan int) <- step             // /!\ utilisation d'un "Type Assertion"
 				time.Sleep(1 * time.Millisecond) // "cool down"
 				<-c.(chan int)
@@ -163,6 +165,8 @@ func (simu *Simulation) Print() {
 		for i := 0; i < 20; i++ {
 			fmt.Println(simu.env.station[i])
 		}
+		fmt.Println()
+		fmt.Println()
 		//time.Sleep(time.Second / 4) // 60 fps !
 		time.Sleep(500 * time.Millisecond) // 1 fps !
 		//fmt.Print("\033[H\033[2J") // effacement du terminal
diff --git a/internal/simulation/usagerLambda.go b/internal/simulation/usagerLambda.go
index 843be37..1041644 100644
--- a/internal/simulation/usagerLambda.go
+++ b/internal/simulation/usagerLambda.go
@@ -5,19 +5,27 @@ import (
 	"time"
 )
 
-type UsagerLambda struct{}
+type UsagerLambda struct{
+	req Request
+}
 
 func (ul *UsagerLambda) Percept(ag *Agent) {
-	ag.stuck = ag.isStuck()
-	if ag.stuck {
-		return
-
+	// récupérer le channel de l'agent lambda
+	chan_agt := ag.env.GetAgentChan(ag.id) 
+	select {
+	case req := <-chan_agt : //verifier si l'agent est communiqué par un autre agent, par exemple un controleur lui a demandé de s'arreter
+		ul.req = req
+	case <- time.After(time.Second):
+		ag.stuck = ag.isStuck()
 	}
-
 }
 
 func (ul *UsagerLambda) Deliberate(ag *Agent) {
-	if ag.stuck {
+	if ul.req.decision == Wait{
+		ag.decision = Wait
+	} else if ul.req.decision == Expel{
+		ag.decision = Expel
+	} else if ag.stuck {
 		ag.decision = Wait
 	} else {
 		ag.decision = Move
@@ -30,6 +38,24 @@ 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 {
+		ag.destination = ul.findNearestExit(ag.env)
+		ag.MoveAgent()
 	}
+}
 
+
+/*
+ * Fonction qui permet de trouver la sortie la plus proche
+*/
+func (ul *UsagerLambda) findNearestExit(env *Environment) Coord{
+	station := env.station
+	for i := 0; i < len(station); i++ {
+		for j := 0; j < len(station[i]); j++ {
+			if station[i][j] == "X" {
+				return Coord{i,j}
+			}
+		}
+	}
+	return Coord{0,0}
 }
-- 
GitLab