Skip to content
Snippets Groups Projects
Commit 11cf0bfb authored by julienpillis's avatar julienpillis
Browse files

déplacement avec orientation

parent baf5115b
No related branches found
No related tags found
3 merge requests!5déplacement avec orientation,!4Multiple pixels agt,!2Agents
......@@ -2,13 +2,12 @@ package algorithms
import (
"container/heap"
"fmt"
)
/*
* 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
......@@ -16,7 +15,7 @@ type Node struct {
func NewNode(row, col, cost, heuristic, width, height int) *Node {
//fmt.Println()
return &Node{row, col, cost, heuristic, width , height, 0}
return &Node{row, col, cost, heuristic, width, height, 0}
}
func (nd *Node) Row() int {
......@@ -27,6 +26,10 @@ func (nd *Node) Col() int {
return nd.col
}
func (nd *Node) Or() int {
return nd.orientation
}
type PriorityQueue []*Node
func (pq PriorityQueue) Len() int { return len(pq) }
......@@ -110,7 +113,7 @@ func FindPath(matrix [20][20]string, start, end Node, forbidenCell Node) []Node
}
func getNeighbors(matrix [20][20]string, current, end Node, forbiddenCell Node) []*Node {
fmt.Println("okkk")
//fmt.Println("okk")
neighbors := make([]*Node, 0)
// Possible moves: up, down, left, right, rotate (clockwise)
......@@ -118,19 +121,23 @@ func getNeighbors(matrix [20][20]string, current, end Node, forbiddenCell Node)
for _, move := range possibleMoves {
newRow, newCol := current.row+move[0], current.col+move[1]
// Check if the new position is valid, considering agent dimensions and rotation
if isValidMove(matrix, current, forbiddenCell, newRow, newCol) {
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,
})
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) {
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,
})
}
}
}
return neighbors
......@@ -160,13 +167,13 @@ func isValidMove(matrix [20][20]string, current Node, forbiddenCell Node, newRow
}
// Check if the agent fits in the new position, considering its dimensions and rotation
for i := 0; i < current.height; i++ {
for j := 0; j < current.width; j++ {
// Calculate the rotated coordinates based on the agent's orientation
rotatedI, rotatedJ := rotateCoordinates(i, j, current.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++ {
// Calculate the absolute coordinates in the matrix
absRow, absCol := newRow+rotatedI, newCol+rotatedJ
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]) {
......@@ -189,9 +196,7 @@ func isValidMove(matrix [20][20]string, current Node, forbiddenCell Node, newRow
}
func rotateCoordinates(i, j, orientation int) (rotatedI, rotatedJ int) {
// Rotate the coordinates based on the agent's orientation
// You need to implement the logic for rotation based on your specific rules
// This is a simple example that assumes the agent can rotate in all directions
switch orientation {
case 0: // No rotation
rotatedI, rotatedJ = i, j
......@@ -205,3 +210,36 @@ func rotateCoordinates(i, j, orientation int) (rotatedI, rotatedJ int) {
return rotatedI, rotatedJ
}
func calculateBounds(row, col, width, height, orientation int) (infRow, supRow, infCol, supCol int) {
borneInfRow := 0
borneSupRow := 0
borneInfCol := 0
borneSupCol := 0
// Calcul des bornes de position de l'agent après mouvement
switch orientation {
case 0:
borneInfRow = row - width + 1
borneSupRow = row + 1
borneInfCol = col
borneSupCol = col + height
case 1:
borneInfRow = row
borneSupRow = row + height
borneInfCol = col
borneSupCol = col + width
case 2:
borneInfRow = row
borneSupRow = row + width
borneInfCol = col
borneSupCol = col + height
case 3:
borneInfRow = row
borneSupRow = row + height
borneInfCol = col - width + 1
borneSupCol = col + 1
}
return borneInfRow, borneSupRow, borneInfCol, borneSupCol
}
......@@ -3,7 +3,6 @@ package simulation
/*
* Classe et méthodes principales de la structure Agent
* à faire :
* //TODO: gérer les orientations
* // 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
......@@ -11,13 +10,11 @@ package simulation
*/
import (
//"fmt"
"fmt"
"log"
"math/rand"
alg "metrosim/internal/algorithms"
"time"
"fmt"
)
type Action int64
......@@ -48,6 +45,7 @@ type Agent struct {
stuck bool
width int
height int
orientation int
}
type Behavior interface {
......@@ -58,8 +56,8 @@ 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)
return &Agent{AgentID(id), vitesse, force, politesse, departure, departure, destination, behavior, env, syncChan, Noop, isOn, false, width, height}
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}
}
func (ag *Agent) ID() AgentID {
......@@ -87,21 +85,28 @@ func (ag *Agent) Act(env *Environment) {
}
}
func IsMovementSafe(path []alg.Node, ag *Agent, env *Environment) bool {
func IsMovementSafe(path []alg.Node, agt *Agent, env *Environment) bool {
// Détermine si le movement est faisable
if len(path) <= 0 {
return false
}
startX, startY := ag.position[1], ag.position[0]
width, height := ag.width, ag.height
// on simule son nouvel emplacement
// et regarde s'il chevauche un autre agent
for i := path[0].Row(); i < path[0].Row()+ag.height; i++ {
for j := path[0].Col(); j < path[0].Col()+ag.width; j++ {
// Simulation du déplacement
ag := *agt
ag.position = Coord{path[0].Row(), path[0].Col()}
rotateAgent(&ag, path[0].Or())
if !(j >= startX && j < startX+width && i >= startY && i < startY+height) && (env.station[i][j] != "B" && env.station[i][j] != "_") {
// Si on est sur une case non atteignable, en dehors de la zone qu'occupe l'agent avant déplacement, on est bloqué
// 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
}
}
......@@ -109,27 +114,32 @@ func IsMovementSafe(path []alg.Node, ag *Agent, env *Environment) bool {
return true
}
func IsAgentBlocking(path []alg.Node, ag *Agent, env *Environment) bool {
func IsAgentBlocking(path []alg.Node, agt *Agent, env *Environment) bool {
// Détermine si un agent se trouve sur la case à visiter
// Coordonnée de départ et dimensions du rectangle
if len(path) <= 0 {
return false
}
startX, startY := ag.position[1], ag.position[0]
width, height := ag.width, ag.height
// on simule son nouvel emplacement
// et regarde s'il chevauche un autre agent
for i := path[0].Row(); i < path[0].Row()+ag.height; i++ {
for j := path[0].Col(); j < path[0].Col()+ag.width; j++ {
// 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)
if !(j >= startX && j < startX+width && i >= startY && i < startY+height) && env.station[i][j] == "A" {
// 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
}
}
}
return false
}
......@@ -137,33 +147,28 @@ func (ag *Agent) isStuck() bool {
// Perception des éléments autour de l'agent pour déterminer si bloqué
not_acc := 0 // nombre de cases indisponibles autour de l'agent
// Coordonnée de départ et dimensions du rectangle
startX, startY := ag.position[1], ag.position[0]
width, height := ag.width, ag.height
count := 0
// Largeur et hauteur du rectangle étendu
extendedWidth := width + 2 // +2 pour les cases à gauche et à droite du rectangle
extendedHeight := height + 2 // +2 pour les cases au-dessus et en dessous du rectangle
// Calcul des bornes de position de l'agent après mouvement
borneInfRow, borneSupRow, borneInfCol, borneSupCol := calculateBounds(ag.position, ag.width, ag.height, ag.orientation)
count := 0
// Parcourir les cases autour du rectangle
for i := startX - 1; i < startX+extendedWidth-1; i++ {
for j := startY - 1; j < startY+extendedHeight-1; j++ {
for i := borneInfRow - 1; i < borneSupRow+1; i++ {
for j := borneInfCol - 1; j < borneSupCol+1; j++ {
// Éviter les cases à l'intérieur du rectangle
if i >= startX && i < startX+width && j >= startY && j < startY+height {
if i >= borneInfRow && i < borneSupRow && j >= borneInfCol && j < borneSupCol {
continue
} else {
count++
}
// Case inaccessible
if ag.env.station[j][i] == "X" || ag.env.station[j][i] == "Q" || ag.env.station[j][i] == "A" {
if i < 0 || j < 0 || i > 19 || j > 19 || ag.env.station[i][j] == "X" || ag.env.station[i][j] == "Q" || ag.env.station[i][j] == "A" {
not_acc++
}
// fmt.Printf("Border (%d, %d) = %s \n", j, i,ag.env.station[j][i])
// fmt.Printf("Border (%d, %d) = %s \n", i, j, ag.env.station[i][j])
}
}
// Si aucune case disponible autour de lui, il est bloqué
return not_acc == count
}
......@@ -174,9 +179,11 @@ func (ag *Agent) MoveAgent() {
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))
// ================== Etude de faisabilité =======================
fmt.Println(path)
// 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
time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
......@@ -185,10 +192,11 @@ func (ag *Agent) MoveAgent() {
}
if IsMovementSafe(path, ag, ag.env) {
removeAgent(&ag.env.station, ag)
rotateAgent(ag, path[0].Or())
//ag.env.station[ag.coordBasOccupation[0]][ag.coordBasOccupation[1]] = ag.isOn
ag.position[0] = path[0].Row()
ag.position[1] = path[0].Col()
saveCells(&ag.env.station, ag.isOn, ag.position, ag.width, ag.height)
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 ======================
......@@ -201,8 +209,12 @@ func (ag *Agent) MoveAgent() {
func removeAgent(matrix *[20][20]string, agt *Agent) {
// Supprime l'agent de la matrice
for i := agt.position[0]; i < agt.position[0]+agt.height; i++ {
for j := agt.position[1]; j < agt.position[1]+agt.width; j++ {
// Calcul des bornes de position de l'agent
borneInfRow, borneSupRow, borneInfCol, borneSupCol := calculateBounds(agt.position, agt.width, agt.height, agt.orientation)
for i := borneInfRow; i < borneSupRow; i++ {
for j := borneInfCol; j < borneSupCol; j++ {
matrix[i][j] = agt.isOn[Coord{i, j}]
removeCoord(Coord{i, j}, agt.isOn)
}
......@@ -210,18 +222,25 @@ func removeAgent(matrix *[20][20]string, agt *Agent) {
}
func writeAgent(matrix *[20][20]string, agt *Agent) {
// Ecris un agent dans la matrice
for i := agt.position[0]; i < agt.position[0]+agt.height; i++ {
for j := agt.position[1]; j < agt.position[1]+agt.width; j++ {
// Ecris l'agent dans la matrice
// Calcul des bornes de position de l'agent
borneInfRow, borneSupRow, borneInfCol, borneSupCol := calculateBounds(agt.position, agt.width, agt.height, agt.orientation)
for i := borneInfRow; i < borneSupRow; i++ {
for j := borneInfCol; j < borneSupCol; j++ {
matrix[i][j] = "A"
}
}
}
func saveCells(matrix *[20][20]string, savedCells map[Coord]string, ref Coord, width, height int) {
func saveCells(matrix *[20][20]string, savedCells map[Coord]string, position Coord, width, height, orientation int) {
// Enregistrement des valeurs des cellules de la matrice
for i := ref[0]; i < ref[0]+height; i++ {
for j := ref[1]; j < ref[1]+width; j++ {
borneInfRow, borneSupRow, borneInfCol, borneSupCol := calculateBounds(position, width, height, orientation)
for i := borneInfRow; i < borneSupRow; i++ {
for j := borneInfCol; j < borneSupCol; j++ {
savedCells[Coord{i, j}] = matrix[i][j]
}
}
......@@ -235,3 +254,40 @@ func removeCoord(to_remove Coord, mapping map[Coord]string) {
}
}
}
func rotateAgent(agt *Agent, orientation int) {
agt.orientation = orientation
}
func calculateBounds(position Coord, width, height, orientation int) (infRow, supRow, infCol, supCol int) {
borneInfRow := 0
borneSupRow := 0
borneInfCol := 0
borneSupCol := 0
// Calcul des bornes de position de l'agent après mouvement
switch orientation {
case 0:
borneInfRow = position[0] - width + 1
borneSupRow = position[0] + 1
borneInfCol = position[1]
borneSupCol = position[1] + height
case 1:
borneInfRow = position[0]
borneSupRow = position[0] + height
borneInfCol = position[1]
borneSupCol = position[1] + width
case 2:
borneInfRow = position[0]
borneSupRow = position[0] + width
borneInfCol = position[1]
borneSupCol = position[1] + height
case 3:
borneInfRow = position[0]
borneSupRow = position[0] + height
borneInfCol = position[1] - width + 1
borneSupCol = position[1] + 1
}
return borneInfRow, borneSupRow, borneInfCol, borneSupCol
}
......@@ -87,8 +87,8 @@ func NewSimulation(agentCount int, maxStep int, maxDuration time.Duration) (simu
// Communication entre agents
mapChan := make(map[AgentID]chan AgentID)
//simu.env = *NewEnvironment([]Agent{}, carte, mapChan)
simu.env = *NewEnvironment([]Agent{}, playground, mapChan)
simu.env = *NewEnvironment([]Agent{}, carte, mapChan)
//simu.env = *NewEnvironment([]Agent{}, playground, mapChan)
// création des agents et des channels
for i := 0; i < agentCount; i++ {
......@@ -97,8 +97,8 @@ 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{5, 8}, Coord{7, 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{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)
// ajout de l'agent à la simulation
simu.agents = append(simu.agents, *ag)
......@@ -164,7 +164,7 @@ func (simu *Simulation) Print() {
fmt.Println(simu.env.station[i])
}
//time.Sleep(time.Second / 4) // 60 fps !
time.Sleep(time.Second) // 1 fps !
time.Sleep(500 * time.Millisecond) // 1 fps !
//fmt.Print("\033[H\033[2J") // effacement du terminal
}
}
......
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