Skip to content
Snippets Groups Projects
Unverified Commit bdb9e462 authored by Kat Marchán's avatar Kat Marchán
Browse files

Consideration->Scorer, Utility->Score

Fixes: https://github.com/zkat/big-brain/issues/3
parent ae4ebb7e
No related branches found
No related tags found
No related merge requests found
......@@ -3,10 +3,10 @@ use quote::quote;
use syn::{parse_macro_input, DeriveInput};
use action::Action;
use consideration::Consideration;
use scorer::Scorer;
mod action;
mod consideration;
mod scorer;
/**
`Action`s in `big-brain` are defined through this derive macro. Once defined,
......@@ -198,9 +198,9 @@ impl<'a> System<'a> for ConsiderHunger {
)
```
*/
#[proc_macro_derive(Consideration, attributes(consideration))]
pub fn derive_consideration_builder(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
#[proc_macro_derive(Scorer, attributes(scorer))]
pub fn derive_scorer_builder(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let consideration = Consideration::from_derive_input(&input).unwrap();
(quote!(#consideration)).into()
let scorer = Scorer::from_derive_input(&input).unwrap();
(quote!(#scorer)).into()
}
......@@ -3,16 +3,16 @@ use proc_macro2::TokenStream;
use quote::quote;
#[derive(Debug, FromDeriveInput)]
#[darling(attributes(consideration), supports(struct_named))]
pub struct Consideration {
#[darling(attributes(scorer))]
pub struct Scorer {
ident: syn::Ident,
generics: syn::Generics,
data: ast::Data<(), ConsiderationField>,
data: ast::Data<(), ScorerField>,
}
#[derive(Debug, FromField)]
#[darling(attributes(consideration))]
struct ConsiderationField {
#[darling(attributes(scorer))]
struct ScorerField {
ident: Option<syn::Ident>,
ty: syn::Type,
#[darling(default)]
......@@ -21,9 +21,9 @@ struct ConsiderationField {
default: bool,
}
impl ToTokens for Consideration {
impl ToTokens for Scorer {
fn to_tokens(&self, tokens: &mut TokenStream) {
let Consideration {
let Scorer {
ref ident,
ref data,
..
......@@ -34,7 +34,7 @@ impl ToTokens for Consideration {
.expect("Enums not supported")
.fields;
let field_defs = fields.clone().into_iter().filter_map(|field| {
let ConsiderationField {
let ScorerField {
ident, ty, param, ..
} = field;
let ident = ident.clone().unwrap();
......@@ -45,7 +45,7 @@ impl ToTokens for Consideration {
}
});
let field_assignments = fields.into_iter().map(|field| {
let ConsiderationField {
let ScorerField {
ident,
param,
default,
......@@ -69,10 +69,10 @@ impl ToTokens for Consideration {
}
});
let ts = quote! {
mod big_brain_cons_builder {
mod big_brain_scorer_builder {
use super::#ident as Comp;
use big_brain::{typetag, serde::Deserialize, Consideration, bevy::prelude::*, ConsiderationEnt};
use big_brain::{typetag, serde::Deserialize, Scorer, bevy::prelude::*, ScorerEnt};
// use typetag;
#[derive(Debug, Deserialize)]
......@@ -80,11 +80,11 @@ impl ToTokens for Consideration {
#(#field_defs),*
}
#[typetag::deserialize]
impl Consideration for #ident {
fn build(&self, actor: Entity, cmd: &mut Commands) -> ConsiderationEnt {
let ent = ConsiderationEnt(cmd.spawn().id());
impl Scorer for #ident {
fn build(&self, actor: Entity, cmd: &mut Commands) -> ScorerEnt {
let ent = ScorerEnt(cmd.spawn().id());
cmd.entity(ent.0)
.insert(big_brain::Utility::default())
.insert(big_brain::Score::default())
.insert(Comp {
#(#field_assignments),*
});
......
......@@ -20,9 +20,7 @@ impl Thirst {
pub fn thirst_system(time: Res<Time>, mut thirsts: Query<&mut Thirst>) {
for mut thirst in thirsts.iter_mut() {
thirst.thirst +=
thirst.per_second * (time.delta().as_micros() as f32 / 1000000.0);
println!("Getting thirstier...{}%", thirst.thirst);
thirst.thirst += thirst.per_second * (time.delta().as_micros() as f32 / 1000000.0);
}
}
......@@ -76,29 +74,29 @@ fn drink_action_system(
}
}
// Then, we have something called "Considerations". These are special
// components that run in the background, calculating a "Utility" value, which
// is what Big Brain will use to pick which actions to execute.
// Then, we have something called "Scorers". These are special components that
// run in the background, calculating a "Score" value, which is what Big Brain
// will use to pick which actions to execute.
//
// Additionally, though, we pull in an evaluator and define a weight. Which is
// just mathy stuff you can tweak to get the behavior you want. More on this
// in the docs (later), but for now, just put them in there and trust the
// system. :)
#[derive(Debug, Consideration)]
pub struct ThirstConsideration {
#[consideration(default)]
#[derive(Debug, Scorer)]
pub struct ScoreThirst {
#[scorer(default)]
pub evaluator: PowerEvaluator,
#[consideration(param)]
#[scorer(param)]
pub weight: f32,
}
// Look familiar? Similar dance to Actions here.
pub fn thirst_consideration_system(
pub fn score_thirst_system(
thirsts: Query<&Thirst>,
// Same dance with the Parent here, but now we've added a Utility!
mut query: Query<(&Parent, &ThirstConsideration, &mut Utility)>,
mut query: Query<(&Parent, &ScoreThirst, &mut Score)>,
) {
for (Parent(actor), conser, mut util) in query.iter_mut() {
for (Parent(actor), scorer, mut score) in query.iter_mut() {
if let Ok(thirst) = thirsts.get(*actor) {
// This is really what the job of a Consideration is. To calculate
// a generic Utility value that the Big Brain engine will compare
......@@ -111,9 +109,9 @@ pub fn thirst_consideration_system(
// literally just use linear values here and set thresholds
// accordingly. The evaluator is just there to give the value a
// bit of a curve.
*util = Utility {
value: conser.evaluator.evaluate(thirst.thirst),
weight: conser.weight,
*score = Score {
value: scorer.evaluator.evaluate(thirst.thirst),
weight: scorer.weight,
};
}
}
......@@ -157,7 +155,7 @@ fn main() {
.add_plugin(BigBrainPlugin)
.add_startup_system(init_entities.system())
.add_system(thirst_system.system())
.add_system(thirst_consideration_system.system())
.add_system(score_thirst_system.system())
.add_system(drink_action_system.system())
.run();
}
......@@ -3,20 +3,20 @@ use serde::Deserialize;
use crate::{
actions::{Action, ActionState},
considerations::{Consideration, Utility},
scorers::{Scorer, Score},
measures::{Measure, WeightedMeasure},
thinker::{ActionEnt, ConsiderationEnt},
thinker::{ActionEnt, ScorerEnt},
};
// Contains different types of Considerations and Actions
#[derive(Debug)]
pub struct Choice {
pub measure: Box<dyn Measure>,
pub utilities: Vec<ConsiderationEnt>,
pub utilities: Vec<ScorerEnt>,
pub action_state: ActionEnt,
}
impl Choice {
pub fn calculate(&self, utilities: &Query<&Utility>) -> f32 {
pub fn calculate(&self, utilities: &Query<&Score>) -> f32 {
self.measure.calculate(
self.utilities
.iter()
......@@ -32,7 +32,7 @@ impl Choice {
#[derive(Debug, Deserialize)]
pub struct ChoiceBuilder {
pub consider: Vec<Box<dyn Consideration>>,
pub consider: Vec<Box<dyn Scorer>>,
pub then: Box<dyn Action>,
}
impl ChoiceBuilder {
......
......@@ -5,7 +5,7 @@ pub use typetag;
pub use actions::*;
pub use choices::*;
pub use considerations::*;
pub use scorers::*;
pub use thinker::*;
pub mod evaluators;
......@@ -14,7 +14,7 @@ pub mod pickers;
mod actions;
mod choices;
mod considerations;
mod scorers;
mod thinker;
use bevy::prelude::*;
......
use serde::{Deserialize, Serialize};
use crate::Utility;
use crate::Score;
#[typetag::serde]
pub trait Measure: std::fmt::Debug + Sync + Send {
fn calculate(&self, utilities: Vec<&Utility>) -> f32;
fn calculate(&self, utilities: Vec<&Score>) -> f32;
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
......@@ -12,7 +12,7 @@ pub struct WeightedMeasure;
#[typetag::serde]
impl Measure for WeightedMeasure {
fn calculate(&self, utilities: Vec<&Utility>) -> f32 {
fn calculate(&self, utilities: Vec<&Score>) -> f32 {
let wsum: f32 = utilities.iter().map(|el| el.weight).sum();
if wsum == 0.0 {
0.0
......
......@@ -2,11 +2,11 @@ use bevy::prelude::*;
use serde::{Deserialize, Serialize};
use crate::{choices::Choice, considerations::Utility, thinker::ActionEnt};
use crate::{choices::Choice, scorers::Score, thinker::ActionEnt};
#[typetag::serde]
pub trait Picker: std::fmt::Debug + Sync + Send {
fn pick(&self, _choices: &[Choice], _utilities: &Query<&Utility>) -> Option<ActionEnt>;
fn pick(&self, _choices: &[Choice], _utilities: &Query<&Score>) -> Option<ActionEnt>;
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
......@@ -16,7 +16,7 @@ pub struct FirstToScore {
#[typetag::serde]
impl Picker for FirstToScore {
fn pick(&self, choices: &[Choice], utilities: &Query<&Utility>) -> Option<ActionEnt> {
fn pick(&self, choices: &[Choice], utilities: &Query<&Score>) -> Option<ActionEnt> {
for choice in choices {
let value = choice.calculate(utilities);
if value >= self.threshold {
......
use bevy::prelude::*;
use crate::ConsiderationEnt;
use crate::ScorerEnt;
#[derive(Debug, Clone, Default)]
pub struct Utility {
pub struct Score {
pub value: f32,
pub weight: f32,
}
......@@ -12,6 +12,6 @@ pub struct Utility {
This trait defines new considerations. In general, you should use the [derive macro](derive.Consideration.html) instead.
*/
#[typetag::deserialize]
pub trait Consideration: std::fmt::Debug + Sync + Send {
fn build(&self, entity: Entity, cmd: &mut Commands) -> ConsiderationEnt;
pub trait Scorer: std::fmt::Debug + Sync + Send {
fn build(&self, entity: Entity, cmd: &mut Commands) -> ScorerEnt;
}
......@@ -8,7 +8,7 @@ use serde::Deserialize;
use crate::{
actions::{self, Action, ActionManager, ActionManagerWrapper, ActionState},
choices::{Choice, ChoiceBuilder},
considerations::Utility,
scorers::Score,
pickers::Picker,
};
......@@ -16,7 +16,7 @@ use crate::{
pub struct ActionEnt(pub Entity);
#[derive(Debug, Clone, Copy)]
pub struct ConsiderationEnt(pub Entity);
pub struct ScorerEnt(pub Entity);
#[derive(Debug)]
pub struct Thinker {
......@@ -123,7 +123,7 @@ pub fn thinker_system(
mut cmd: Commands,
mut iterations: Local<ThinkerIterations>,
mut thinker_q: Query<(Entity, &Parent, &mut Thinker, &ActiveThinker)>,
utilities: Query<&Utility>,
utilities: Query<&Score>,
mut action_states: Query<&mut actions::ActionState>,
builder_wrappers: Query<&ActionManagerWrapper>,
) {
......
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