From 1a1d5b3d17d96a51084418128f0bfebe0ad8c702 Mon Sep 17 00:00:00 2001
From: alexander <alexanderpaullozada@gmail.com>
Date: Wed, 28 Apr 2021 23:47:10 -0500
Subject: [PATCH] feat(scorers): Added EvaluatingScorer (#24)

* Added EvaluatingScorer

* fixed doc issue

Co-authored-by: doomy <2640792-_doomy@users.noreply.gitlab.com>
---
 src/lib.rs     |  1 +
 src/scorers.rs | 76 +++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 76 insertions(+), 1 deletion(-)

diff --git a/src/lib.rs b/src/lib.rs
index 796c021..c4465f0 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -201,5 +201,6 @@ impl Plugin for BigBrainPlugin {
         app.add_system(scorers::all_or_nothing_system.system());
         app.add_system(scorers::sum_of_scorers_system.system());
         app.add_system(scorers::winning_scorer_system.system());
+        app.add_system(scorers::evaluating_scorer_system.system());
     }
 }
diff --git a/src/scorers.rs b/src/scorers.rs
index b49b02b..eaa0843 100644
--- a/src/scorers.rs
+++ b/src/scorers.rs
@@ -6,7 +6,10 @@ use std::{cmp::Ordering, sync::Arc};
 
 use bevy::prelude::*;
 
-use crate::thinker::{Actor, ScorerEnt};
+use crate::{
+    evaluators::Evaluator,
+    thinker::{Actor, ScorerEnt},
+};
 
 /**
 Score value between `0.0..=1.0` associated with a Scorer.
@@ -357,3 +360,74 @@ impl ScorerBuilder for WinningScorerBuilder {
             });
     }
 }
+
+/**
+Composite scorer that takes a `ScorerBuilder` and applies an `Evaluator`. Note that
+unlike other composite scorers, `EvaluatingScorer` only takes one scorer upon building.
+
+### Example
+
+```ignore
+Thinker::build()
+    .when(
+        EvaluatingScorer::build(MyScorer, MyEvaluator),
+        MyAction::build());
+```
+ */
+#[derive(Debug, Clone)]
+pub struct EvaluatingScorer {
+    scorer: ScorerEnt,
+    evaluator: Arc<dyn Evaluator>,
+}
+
+impl EvaluatingScorer {
+    pub fn build(
+        scorer: impl ScorerBuilder + 'static,
+        evaluator: impl Evaluator + 'static,
+    ) -> EvaluatingScorerBuilder {
+        EvaluatingScorerBuilder {
+            evaluator: Arc::new(evaluator),
+            scorer: Arc::new(scorer),
+        }
+    }
+}
+
+pub fn evaluating_scorer_system(
+    query: Query<(Entity, &EvaluatingScorer)>,
+    mut scores: QuerySet<(Query<&Score>, Query<&mut Score>)>,
+) {
+    for (sos_ent, eval_scorer) in query.iter() {
+        // Get the inner score
+        let inner_score = scores
+            .q0()
+            .get(eval_scorer.scorer.0)
+            .expect("where did it go?")
+            .get();
+        // Get composite score
+        let mut score = scores.q1_mut().get_mut(sos_ent).expect("where did it go?");
+        score.set(crate::evaluators::clamp(
+            eval_scorer.evaluator.evaluate(inner_score),
+            0.0,
+            1.0,
+        ));
+    }
+}
+
+#[derive(Debug, Clone)]
+pub struct EvaluatingScorerBuilder {
+    pub scorer: Arc<dyn ScorerBuilder>,
+    pub evaluator: Arc<dyn Evaluator>,
+}
+
+impl ScorerBuilder for EvaluatingScorerBuilder {
+    fn build(&self, cmd: &mut Commands, scorer: Entity, actor: Entity) {
+        let inner_scorer = self.scorer.attach(cmd, actor);
+        cmd.entity(scorer)
+            .insert(Transform::default())
+            .insert(GlobalTransform::default())
+            .insert(EvaluatingScorer {
+                evaluator: self.evaluator.clone(),
+                scorer: ScorerEnt(inner_scorer),
+            });
+    }
+}
-- 
GitLab