diff --git a/backend/server/websocketserver.go b/backend/server/websocketserver.go index be4d53beeeb0ef2d6a98c4d51944eb0268873a5c..f8985d97ea7e53e0a3332fa4bd5d1951a40e9cfa 100644 --- a/backend/server/websocketserver.go +++ b/backend/server/websocketserver.go @@ -100,6 +100,10 @@ func (server *WebSocketServer) startSimulation(w http.ResponseWriter, r *http.Re case "bye": conn.Close() conn = nil + case "addBee": + if server.simulation != nil { + server.simulation.AddBee() + } } } } diff --git a/backend/simulation/environment/environment.go b/backend/simulation/environment/environment.go index 1fccf531912a4ceb4b338727be2643be4ed99a82..db676c4f490317c361c250ecf4ed6526591da9fe 100644 --- a/backend/simulation/environment/environment.go +++ b/backend/simulation/environment/environment.go @@ -210,3 +210,7 @@ func (env *Environment) ToJsonObj() interface{} { func (env *Environment) GetHive() IObject { return env.objs[0] } + +func (env *Environment) GetNumberAgent() int { + return len(env.agts) +} diff --git a/backend/simulation/object/flower.go b/backend/simulation/object/flower.go index 53de40bd1f19ca5eb4d46e76c97857601eb9c8a4..6920b55c8485e276dfeb78380d290f585790812f 100644 --- a/backend/simulation/object/flower.go +++ b/backend/simulation/object/flower.go @@ -93,7 +93,10 @@ func (f *Flower) Become(f2 interface{}) { func (f *Flower) Update() { addedNectar := utils.GetProducedNectarPerTurn() - f.nectar = (addedNectar + f.nectar) % f.maxNectar + f.nectar = (addedNectar + f.nectar) + if f.nectar > f.maxNectar { + f.nectar = f.maxNectar + } } func (f Flower) ToJsonObj() interface{} { diff --git a/backend/simulation/object/hive.go b/backend/simulation/object/hive.go index d1c0e8861abddb58504c67b675e625edc8143a03..32488be1decddd2d73638815eb64ae23e9c463db 100644 --- a/backend/simulation/object/hive.go +++ b/backend/simulation/object/hive.go @@ -80,6 +80,10 @@ func (h *Hive) Become(h_alt interface{}) { } func (h *Hive) Update() { + h.qNectar -= h.env.GetNumberAgent() - utils.GetNumberHornets() + if h.qNectar < 0 { + h.qNectar = 0 + } if h.qNectar > 0 { h.qHoney += 1 h.qNectar -= 1 @@ -122,6 +126,13 @@ func (h Hive) TypeObject() envpkg.ObjectType { return envpkg.Hive } +func (h Hive) GetHoney() int { + return h.qHoney +} + +func (h *Hive) RetreiveHoney(honey int) { + h.qHoney -= honey +} func (h *Hive) AddFlower(flower *Flower) { h.flowerStack.Push(flower) } diff --git a/backend/simulation/simulation.go b/backend/simulation/simulation.go index 8b870b2affe2c6df1a2b72eaaf3546b079a24b5d..97cb70c4f44ba3fa60006438dc6bad2e0974a624 100644 --- a/backend/simulation/simulation.go +++ b/backend/simulation/simulation.go @@ -21,6 +21,7 @@ type Simulation struct { objs []envpkg.IObject running bool ws *websocket.Conn + addBee envpkg.IAgent sync.Mutex } @@ -34,6 +35,7 @@ func NewSimulation(nbees int, nflowers int, nhornets int, maWs *websocket.Conn) simu := &Simulation{} simu.ws = maWs env := envpkg.NewEnvironment([]envpkg.IAgent{}, []envpkg.IObject{}) + simu.addBee = nil simu.env = env //On récupère la webSocket mapDimension := utils.GetMapDimension() @@ -193,13 +195,20 @@ func (simu *Simulation) Run(maWs *websocket.Conn) { } } } + if simu.addBee != nil { + simu.env.AddAgent(simu.addBee) + simu.addBee.Start() + simu.agts = append(simu.agts, simu.addBee) + fmt.Printf("{{SIMULATION}} - Bee added\n") + simu.addBee = nil + } for _, obj := range simu.objs { if obj != nil { obj.Update() } } fmt.Printf("\n\n Tour terminé %d\n\n", j) - time.Sleep(time.Second / 100) // 100 Tour / Sec + time.Sleep(time.Second / 3) // 100 Tour / Sec j++ } @@ -228,7 +237,7 @@ func (simu *Simulation) log() { } for simu.IsRunning() { simu.sendState() - time.Sleep(time.Second / 60) // 60 fps + time.Sleep(time.Second / 3) // 60 fps } } @@ -266,3 +275,25 @@ func (simu *Simulation) ToJsonObj() SimulationJson { return SimulationJson{Agents: agents, Objects: objects, Environment: simu.env.ToJsonObj()} } + +func (simu *Simulation) AddBee() bool { + if !simu.IsRunning() && simu.addBee != nil { + return false + } + cost := utils.GetBeeCreationCost() + hive := simu.objs[0].(*obj.Hive) + // Creating a bee + if simu.IsRunning() && hive.GetHoney() > cost { + hive.RetreiveHoney(cost) + } + id := fmt.Sprintf("Bee #%d", len(simu.agts)) + syncChan := make(chan envpkg.AgentID) + agt := agt.NewBeeAgent(id, simu.env, syncChan, rand.Intn(2)+1, hive, time.Now(), utils.GetMaxNectar(), agt.Worker) + // ajout de l'agent à l'environnement + simu.Lock() + simu.env.Lock() + simu.addBee = agt + simu.env.Unlock() + simu.Unlock() + return true +} diff --git a/backend/utils/configreader.go b/backend/utils/configreader.go index f8e2a485fa89f7957ccda6e50dcb3ff66d5b7682..97ebe282a00fec053b57d30c48e34cd7092547a6 100644 --- a/backend/utils/configreader.go +++ b/backend/utils/configreader.go @@ -100,3 +100,7 @@ func GetHornetAgentVisionRange() float64 { func GetExName() string { return getStringAttributeFromConfigFile("ExName") } + +func GetBeeCreationCost() int { + return getIntAttributeFromConfigFile("BeeCreationCost") +} diff --git a/config.yaml b/config.yaml index beef462cfe115b39dfc77425ff1ec7936e3013ee..60a5125bf2b1898b5e23522893f69faa11e08186 100644 --- a/config.yaml +++ b/config.yaml @@ -2,16 +2,17 @@ MapDimension: 30 # Bees -NumberBees: 20 +NumberBees: 5 BeeAgentVisionRange: 4.0 MaxNectar: 70 # in mg -> https://wildflowermeadows.com/2024/01/how-far-do-honeybees-fly/ +BeeCreationCost: 20 # Hornets -NumberHornets: 3 +NumberHornets: 0 HornetAgentVisionRange: 4.0 # Flowers -NumberFlowers: 10 +NumberFlowers: 14 NumberFlowerPatches: 3 MaxNectarHeld : 80 # in mg, defined as this in the code ProducedNectarPerTurn : 6 # in mg -> https://www.miel-lerucherdelours.fr/en/content/67-the-sunflowers diff --git a/frontend/css/main_style.css b/frontend/css/main_style.css index 12bf2975adeb3a1814d91708d15bf32e5df01cb5..8fca1df4ee51e7cbf763a07d058adadbab2324eb 100644 --- a/frontend/css/main_style.css +++ b/frontend/css/main_style.css @@ -2,11 +2,41 @@ .sidebar { width: 15%; overflow: hidden; - height: 90%; + height: 80%; position: absolute; border: 1px solid #000; } +.boutton-group{ + border-radius: 20%; + width: 100%; + height: 50px; + margin-top: 10px; + margin-bottom: 10px; + text-align: center; + display: flex; + justify-content: space-around; +} + +.boutton-group button{ + width: 10%; + height: 100%; + border-radius: 20%; + border: 1px solid #000; +} + +.boutton-group button:hover{ + background-color: #f0d87f; +} + +.boutton-group .active{ + background-color: #f0d87f; +} + +.boutton-group .inactive{ + background-color: #838280; +} + .nectar-value{ position: absolute; width: 15%; diff --git a/frontend/index.html b/frontend/index.html index e9460af12dfe9d844e2d72c7434ea95c31001dbf..9377141ed4f3d5ec0234c04a39f931a15e0d5c36 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -11,13 +11,15 @@ <body> <h2 id="connection-state">Connection closed</h2> - <div style="display:flex; gap:10px; margin-bottom: 50px;"> + <div class="boutton-group"> <button id="start-simulation">Start simulation</button> <button id="stop-simulation">Stop simulation</button> <button id="new-simulation">New simulation</button> + <button id="add-bee">Add bee</button> </div> <div id="nectar-value"> <p id="nectar"></p> + <p id="honey"></p> </div> <div id="main"> <div class="sidebar"> @@ -31,11 +33,14 @@ const errorsDiv = document.getElementById('errors'); const ocean = document.getElementById('ocean'); const nectar = document.getElementById('nectar'); + const honey = document.getElementById('honey'); + const addBee = document.getElementById('add-bee'); const app = new PIXI.Application(); await app.init({ background: '#ffffff', width: window.innerHeight * 0.9, height: window.innerHeight * 0.9 }); document.getElementById('main').appendChild(app.canvas); app.canvas.style.margin = ' 0% 0% 0% 20%'; + app.canvas.style.border = '1px solid black'; PIXI.Assets.add({ alias: 'beeWorker', src: './res/sprites/beeForager.png' }); PIXI.Assets.add({ alias: 'beeGuardian', src: './res/sprites/beeGuardian.png' }); @@ -89,16 +94,16 @@ } if(elem.id.startsWith('Flower')){ if(elem.gender == "female"){ - if(elem.nectar == 0 && sprite.texture != flowerFemaleBadTexture){ + if(elem.nectar < 20 && sprite.texture != flowerFemaleBadTexture){ sprite.texture = flowerFemaleBadTexture; - }else if(elem.nectar != 0 && sprite.texture != flowerFemaleGoodTexture){ + }else if(elem.nectar > 20 && sprite.texture != flowerFemaleGoodTexture){ sprite.texture = flowerFemaleGoodTexture; } }else{ - if(elem.nectar == 0 && sprite.texture != flowerMaleBadTexture){ + if(elem.nectar < 20 && sprite.texture != flowerMaleBadTexture){ sprite.texture = flowerMaleBadTexture; - }else if(elem.nectar != 0 && sprite.texture != flowerMaleGoodTexture){ + }else if(elem.nectar >20 && sprite.texture != flowerMaleGoodTexture){ sprite.texture = flowerMaleGoodTexture; } } @@ -218,10 +223,6 @@ sprite.height = cellSize; return sprite; } - function updatePollenLevel(percentage) { - const pollenBar = document.getElementById('pollenBar'); - pollenBar.style.height = `${percentage}%`; - } // Fonction pour nettoyer les sprites qui ne sont plus dans la grille function cleanUnusedSprites(agent, objects) { @@ -243,7 +244,7 @@ function drawSidebar(hive, agentsCount) { if (ocean != null) { - let quantity = hive.quantity_nectar / agentsCount - 10; + let quantity = hive.quantity_honey / agentsCount - 10; if (quantity < 0) { quantity = 0; } @@ -255,6 +256,9 @@ if (nectar != null) { nectar.textContent = `Nectar: ${hive.quantity_nectar}`; } + if (honey != null) { + honey.textContent = `Honey: ${hive.quantity_honey}`; + } } const ws = new WebSocket('ws://localhost:8080/ws/'); @@ -290,8 +294,6 @@ document.getElementById('stop-simulation').onclick = () => { ws.send('stop'); - spritesMap.clear(); - app.stage.removeChildren(); } document.getElementById('new-simulation').onclick = () => { @@ -299,6 +301,9 @@ app.stage.removeChildren(); ws.send('new'); } + document.getElementById('add-bee').onclick = () => { + ws.send('addBee'); + } </script> </div> <div id="errors"></div>