src/scripts/component/redox.js   B
last analyzed

Complexity

Total Complexity 46
Complexity/F 2.71

Size

Lines of Code 234
Function Count 17

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 7
Bugs 0 Features 1
Metric Value
cc 0
wmc 46
c 7
b 0
f 1
nc 12
mnd 4
bc 44
fnc 17
dl 0
loc 234
rs 8.3999
bpm 2.5882
cpm 2.7058
noi 0

1 Function

Rating   Name   Duplication   Size   Complexity  
B angular.controller(ꞌct_redoxꞌ) 0 224 1

How to fix   Complexity   

Complexity

Complex classes like src/scripts/component/redox.js often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/**
2
 redox
3
 Component that handles reduction/oxidation and ions.
4
5
 @namespace Components
6
 */
7
'use strict';
8
9
angular.module('game').component('redox', {
10
  templateUrl: 'views/redox.html',
11
  controller: 'ct_redox',
12
  controllerAs: 'ct'
13
});
14
15
angular.module('game').controller('ct_redox', ['state', 'data', 'visibility', 'util', 'format', 'reaction', 'upgrade',
16
  function (state, data, visibility, util, format, reaction, upgradeService) {
17
    let ct = this;
18
    ct.state = state;
19
    ct.data = data;
20
    ct.util = util;
21
    ct.format = format;
22
    ct.reaction = reaction;
23
    ct.upgradeService = upgradeService;
24
    ct.adjustAmount = [1, 10, 25, 100];
25
26
    ct.update = function(player) {
27
      processRedox(player);
28
      processElectronegativity(player);
29
    };
30
31
    function processRedox(player){
32
      for(let slot of player.element_slots){
33
        if(!slot){
34
          continue;
35
        }
36
        for (let redox of slot.redoxes) {
37
          if (!redox.resource || !redox.active || redox.from === redox.to) {
38
            continue;
39
          }
40
41
          let reactant = ct.generateName(redox.element, redox.from);
42
          let power = util.calculateValue(data.global_upgrades.redox_bandwidth.power.base,
43
                data.global_upgrades.redox_bandwidth.power,
44
                player.global_upgrades_current.redox_bandwidth);
45
          let number = Math.min(power, player.resources[reactant]);
46
          let react = ct.redoxReaction(redox);
47
48
          state.reactions.push({number: number, reaction: react});
49
        }
50
      }
51
    }
52
53
    function processElectronegativity(player){
54
      for(let key in data.elements){
55
        let element = data.elements[key];
56
        if(element.electronegativity === 0){
57
          continue;
58
        }
59
        let ions = element.anions.concat(element.cations);
60
		    ions.push(element.main);
61
        for(let resource of ions){
62
          if(player.resources[resource] === 0){
63
            continue;
64
          }
65
          let charge = data.resources[resource].charge || 0;
66
          let probabilities = probabilityDistribution(key, charge);
67
68
          for(let probKey in probabilities){
69
            if(charge === parseInt(probKey, 10)){
70
               continue;
71
             }
72
            let production = Math.floor(probabilities[probKey]*player.resources[resource]);
73
            if(production === 0){
74
              continue;
75
            }
76
            let react = ct.redoxReaction({
77
              element: key,
78
              from: charge,
79
              to: parseInt(probKey, 10)
80
            });
81
            // electronegativity is 'for free'
82
      			react.reactant.eV = 0;
83
            // FIXME: starvation should fix this
84
            if(react.reactant['e-']){
85
              production = Math.min(production, player.resources['e-']);
86
            }
87
            state.reactions.push({number: production, reaction: react});
88
          }
89
        }
90
      }
91
    }
92
93
    function probabilityDistribution(element, charge){
94
    	let prob = {};
95
    	let start = -data.elements[element].electron_affinity.length;
96
    	let end = charge;
97
    	// lower than index, affected by negativity
98
    	rangeProbability(element, prob, start, end, 1, data.elements[element].negative_factor);
99
100
    	prob[charge] = 1;
101
102
    	start = charge+1;
103
    	end = data.elements[element].ionization_energy.length+1;
104
    	// lower than index, affected by positivity
105
    	rangeProbability(element, prob, start, end, -1, data.elements[element].positive_factor);
106
107
    	let sum = 0;
108
    	for(let i in prob){
109
    		sum += prob[i];
110
    	}
111
    	for(let i in prob){
112
    		prob[i] /= sum;
113
    	}
114
    	return prob;
115
    }
116
117
    function rangeProbability(element, prob, start, end, offset, factor){
118
    	for(let i = start; i < end; i++){
119
    		let difference = data.redox[element][i]-data.redox[element][i+offset];
120
    		if(difference <= 0){
121
    			difference = -difference;
122
    		}else{
123
    			difference = 1/difference;
124
    		}
125
    		prob[i] = Math.pow(data.constants.ELECTRONEGATIVITY_CHANCE,Math.abs(i))*factor*difference;
126
    	}
127
    }
128
129
    /* Writes a redox in the form of a reaction so that we can use the reaction
130
    service to process it */
131
    ct.redoxReaction = function (redox) {
132
      let reactant = ct.generateName(redox.element, redox.from);
133
      let product = ct.generateName(redox.element, redox.to);
134
      let energy = redoxEnergy(redox.from, redox.to, redox.element);
135
136
      let react = {
137
        'reactant': {},
138
        'product': {}
139
      };
140
141
      react.reactant[reactant] = 1;
142
      react.product[product] = 1;
143
      if (energy > 0) {
144
        react.reactant.eV = energy;
145
      } else if (energy < 0) {
146
        react.product.eV = -energy;
147
      }
148
149
      let electron = redox.from - redox.to;
150
      if (electron > 0) {
151
        react.reactant['e-'] = electron;
152
      } else if (electron < 0) {
153
        react.product['e-'] = -electron;
154
      }
155
156
      return react;
157
    };
158
159
    /* Calculates how much energy it takes to go from a redox level to another
160
    for a given element */
161
    function redoxEnergy(from, to, element) {
162
      let energyFrom = data.redox[element][from];
163
      let energyTo = data.redox[element][to];
164
      let energy = energyTo - energyFrom;
165
166
      return energy;
167
    }
168
169
    /* Generates the name of a ion, e.g. O3+ */
170
    ct.generateName = function (element, i) {
171
      if (i === 0) {
172
        return data.elements[element].main;
173
      }
174
      let postfix = '';
175
      if (Math.abs(i) > 1) {
176
        postfix = Math.abs(i);
177
      }
178
      postfix += getSign(i);
179
      let name = element + postfix;
180
      return name;
181
    };
182
183
    function getSign(number) {
184
      return number > 0 ? '+' : '-';
185
    }
186
187
    ct.redoxSize = function (player) {
188
      let size = 0;
189
      for(let slot of player.element_slots){
190
        if(!slot){
191
          continue;
192
        }
193
        size += slot.redoxes.length;
194
      }
195
      return size;
196
    };
197
198
    /* Adds a new redox to the player list */
199
    ct.addRedox = function (player, slot) {
200
      if(ct.redoxSize(player) >= util.calculateValue(data.global_upgrades.redox_slots.power.base,
201
            data.global_upgrades.redox_slots.power,
202
            player.global_upgrades.redox_slots)){
203
        return;
204
      }
205
      slot.redoxes.push({
206
        resource: data.elements[slot.element].main,
207
        active: false,
208
        element: slot.element,
209
        from: 0,
210
        to: 1
211
      });
212
    };
213
214
    ct.removeRedox = function (slot, index) {
215
      slot.redoxes.splice(index, 1);
216
    };
217
218
    ct.checkAll = function(slot){
219
      for(let redox of slot.redoxes){
220
        redox.active = slot.active;
221
      }
222
    }
223
224
    ct.visibleRedox = function(slot) {
225
      return slot.redoxes;
226
    };
227
228
    ct.adjustLevel = function(player, upgrade, amount){
229
      player.global_upgrades_current[upgrade] += amount;
230
      // We cap it between 1 and the current max level
231
      player.global_upgrades_current[upgrade] = Math.max(1, Math.min(player.global_upgrades_current[upgrade], player.global_upgrades[upgrade]));
232
    };
233
234
    ct.visibleUpgrades = function() {
235
      return visibility.visible(data.global_upgrades, upgradeService.filterByTag('redoxes'));
236
    };
237
238
    state.registerUpdate('redox', ct.update);
239
  }
240
]);
241