Skip to content

Introducing a new Score Factor

MFHolm edited this page Jan 31, 2018 · 3 revisions

When creating a new score factor the first thing to do is to create a new KeyPerformanceIndicator for the score. This is done in [keyPerformanceIndicators.ts] (https://github.com/ReeemProject/REEEMgame-local/blob/master/ServerModel/gamelogic/keyPerformanceIndicators.ts). As an example the new score is influenced by both the CO2 emissions and the comfortable housing temperature. The code below shows the key performance indicator for the new score.

export class NewScoreKPI extends KeyPerformanceIndicators {

    private benchmark: number = 50;

    CalculateScore(month: number, co2Emissions: Array<CO2Emissions>, comfortableHousingTemperature: Array<ComfortableHousingTemperature>) {
        let calculatedSum = 0;
        for (var organizationID = 0; organizationID <= 1; organizationID++) {
            calculatedSum += co2Emissions[organizationID].getMonthsValue(month) *2;
            calculatedSum += comfortableHousingTemperature[organizationID].getMonthsValue(month);
            calculatedSum = calculatedSum / 3;
        }
        let calculatedScore = calculatedSum / this.benchmark * this._multiplier;
        let score = calculatedScore > 100 ? 100 : (calculatedScore < 0 ? 0 : calculatedScore);
        this.scorePush = score;
    }
}

To make this score influence the overall score it needs to be added to CombinedKPI. This is done by changing the CalculateScore function by modifying the line

this.scorePush = (social.GetMonthsScore(month) + environmental.GetMonthsScore(month) + economic.GetMonthsScore(month)) / 3;

To

this.scorePush = (social.GetMonthsScore(month) + environmental.GetMonthsScore(month) + economic.GetMonthsScore(month) + newScore.GetMonthsScore(month)) / 4;

This calculates the combined score as the average of the (now 4) different factors.

Now the new score has to be added to the main game logic in mainGameLogic.ts. First it needs to be imported using

import { SocialKPI, EnvironmentalKPI, EconomicKPI, CombinedKPI, NewScoreKPI } from './keyPerformanceIndicators';

The a new local variable can be created for the new score by adding:

private newScore = new NewScoreKPI();

Now the score needs to be reset in the ResetWorld() function of GameLogic in the same way as the other scores. This is done by adding

this.newScore.reset();

And

this.newScore.CalculateScore(0, this.co2Emissions, this.comfortableHousingTemperature);

The new score must also be added as an argument to CalculateScore of the combined score here by using the code below.

this.combinedKPI.CalculateScore(0, this.socialKPI, this.environmentalKPI, this.economicKPI, this.newScoreKPI);

The new score also needs to be added to the score history by adding it in the getScoreHistory() function. This is done by changing getScoreHistory() to

getScoreHistory(): { combined: number[], social: number[], economic: number[], environmental: number[], newScore: number[] } {
        var history: { combined: number[], social: number[], economic: number[], environmental: number[], newScore:number[] } = {
            combined: this.combinedKPI.getScore(),
            social: this.socialKPI.getScore(),
            economic: this.economicKPI.getScore(),
            environmental: this.environmentalKPI.getScore(),
            //add new score to history
            newScore: this.newScore.getScore()
        }
        return history;
    }

We need to create a getter for the new score in the same way as the other getters have been created. The code for the new getter is listed below.

getNewScoreKPIAt(p_month) {
        return this.newScoreKPI.GetMonthsScore(p_month);
    }

Now the new score can be added to the CalculateMonthValues function by adding

this.newScoreKPI.CalculateScore(month, this.co2Emissions, this.comfortableHousingTemperature);

The new score also needs to be added as an argument to CalculateScore of the combined score using the code below

this.combinedKPI.CalculateScore(month, this.socialKPI, this.environmentalKPI, this.economicKPI, this.newScoreKPI);

The new score has now been added to the game logic. The next step is to make it visible to the user. This is done by adding a new list item in the score div in the jade file worldView.jade by adding the code below.

li 
  button(id='newScore' title='Click to see the score chart').menuButton New Score:

To update the value of the new score visually this needs to be added to the update function in ScoreViews.ts. This is done by adding

$("#newScore").text("New Score: " + Math.round(p_data.newScore));

For this to work we need to add newScore to the argument p_data. This data comes from the server and to include the new score we need to go into the getScore function in Scenario.ts. By adding the following line, the new score is included in the returned data.

newScore: Math.round(this.m_gameLogic.getNewScoreKPIAt(p_month))

The new score is now visible to the user and is included in the combined score. The next step is to add the new score to score history. The history is located in the file clientSimulationHistory.ts and SimulationHistory.ts. Fyrst the new score is added to the variable m_scoreHistory using the code below:

private m_scoreHistory: { combined: number[], social: number[], economic: number[], environmental: number[], newScore: number[] };

The new score must be added to setScoreHistory:

 public setScoreHistory(p_history: { com: number[], soc: number[], env: number[], eco: number[], newScore: number[] }) {
        this.m_scoreHistory = { combined: p_history.com, economic: p_history.eco, environmental: p_history.env, social: p_history.soc, newScore:p_history.newScore };
    }

And to clone() by adding the new score to copy.m_scoreHistory by adding the line below.

newScore: this.m_scoreHistory.newScore

The new score also needs to be added as an argument to the constructor and included in the argument for setScoreHistory. The new constructor is listed below.

public constructor(p_history?: {
    m_scoreHistory: { combined: number[], social: number[], economic: number[], environmental: number[], newScore:number[] },
    m_indicatorHistory: {}[],
    m_decisionHistory: {}[],
    m_decisionsMadeHistory: { role: string, type: string, value: number }[][],
    m_overlayHistory: { e: number, h: number, a: number, g: number }[][];
}) {
    if (p_history) {
        this.setDecisionHistory(p_history.m_decisionHistory);
        this.setDecisionMadeHistory(p_history.m_decisionsMadeHistory);
        this.setScoreHistory({ com: p_history.m_scoreHistory.combined, soc: p_history.m_scoreHistory.social, env: p_history.m_scoreHistory.environmental, eco: p_history.m_scoreHistory.economic, newScore: p_history.m_scoreHistory.newScore });
        this.setOverlayHistory(p_history.m_overlayHistory);
        this.setIndicatorHistory(p_history.m_indicatorHistory);
    }
}

The new score needs to be added to getScoresFromHistory which then becomes:

 public getScoresFromHistory(p_time): { c: number, s: number, o: number, v: number } {
        var ret: { c: number, s: number, o: number, v: number, newScore: number };
        if (this.m_scoreHistory) {
            ret = {
                c: this.m_scoreHistory.combined[p_time],
                s: this.m_scoreHistory.social[p_time],
                o: this.m_scoreHistory.economic[p_time],
                v: this.m_scoreHistory.environmental[p_time],
                //Adding the new score
                newScore: this.m_scoreHistory.newScore[p_time]
            }
        }
        return ret;
    }

And to addToScoreHistory which becomes:

public addToScoreHistory(p_score: { c: number, s: number, v: number, o: number, newScore:number }) {
        this.m_scoreHistory.combined.push(p_score.c);
        this.m_scoreHistory.social.push(p_score.s);
        this.m_scoreHistory.economic.push(p_score.o);
        this.m_scoreHistory.environmental.push(p_score.v);
        //Add the new score
        this.m_scoreHistory.newScore.push(p_score.newScore);
    }

Finally the new score needs to be added to getHistory. The following needs to be added to the history variable:

newScore: this.m_scoreHistory.newScore,

And the object types needs to be updated accordingly.

Then we need to update the functions in ClientModel.ts which incoke the functions in clientSimulationHistory.ts.

The only thing needed here is to update the types of the arguments of the constructor, changeScenario, addToHistory and tick to include the new score.

The types also need to be changed in the functions constructor, addToHistory and reset in ClientGameModel.ts.

In ClientGameController.ts the types also need to be updated in reset, onTick and onTimeChange.

In FacilitatorModel.ts the types need to be updated in the constructor and in ClientController.ts the type needs to be updated in onScenarioChange.

Now we will modify the score history on the server side by updating SimulationHistory.ts. As on the client side, we start be added the new score to m_scoreHistory so it becomes:

private m_scoreHistory: { combined: number[], social: number[], economic: number[], environmental: number[], newScore: number[] };

Then the new score needs to be added to getHistory by adding the following to the the history variable:

newScore: this.m_scoreHistory.newScore

And the types need to be updated accordingly.

addToScoreHistory needs to be updated to add the new score as well. This is done by adding the line below and updating the type of the argument.

this.m_scoreHistory.newScore.push(p_score.newScore);

clone() needs to be updated to include the new score by adding:

newScore: this.m_scoreHistory.newScore.slice()

Finally the type of setScoreHistory needs to be updated.

The type in getScores() in ModelDev.ts needs to be updated to include the new score.

The new score is now added to the history and is updated when the time slider is dragged back and forth.

As a final touch an event listener can be added to the score button and the new score can be added to the score diagram. The event listener should be added in ClientGameController.ts. The event listener should be added in the constructor by adding the following code:

$("#newScore").on('click', this.handleNewScore);

And then creating the function handleNewScore which is listed below.

private handleNewScore = () => {
        this.m_view.openDialog(DialogKeys.ScoreDialog, this.m_model.getScoreDialogData());
    }

Now we need to update getScoreDialogData() in ClientGameModel.ts. First we add a label for the new score by adding the line below to to data[0].

{label: 'New Score'}

And by adding the line below to the for loop.

data[i + 1][7] = this.m_history.getHistory().newScore[i];

The new score has now been added to the game and is ready to use. You are encouraged to update the welcome message in WelcomeDialog.ts to include the new score in the explanation.

The code that has been used in this example to add this new score to the game is included in the source code. Some of the code has been commented out to prevent it from influencing the game before it is ready.