Micropolis
evaluate.cpp
Go to the documentation of this file.
1 /* evaluate.cpp
2  *
3  * Micropolis, Unix Version. This game was released for the Unix platform
4  * in or about 1990 and has been modified for inclusion in the One Laptop
5  * Per Child program. Copyright (C) 1989 - 2007 Electronic Arts Inc. If
6  * you need assistance with this program, you may contact:
7  * http://wiki.laptop.org/go/Micropolis or email micropolis@laptop.org.
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or (at
12  * your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * General Public License for more details. You should have received a
18  * copy of the GNU General Public License along with this program. If
19  * not, see <http://www.gnu.org/licenses/>.
20  *
21  * ADDITIONAL TERMS per GNU GPL Section 7
22  *
23  * No trademark or publicity rights are granted. This license does NOT
24  * give you any right, title or interest in the trademark SimCity or any
25  * other Electronic Arts trademark. You may not distribute any
26  * modification of this program using the trademark SimCity or claim any
27  * affliation or association with Electronic Arts Inc. or its employees.
28  *
29  * Any propagation or conveyance of this program must include this
30  * copyright notice and these terms.
31  *
32  * If you convey this program (or any modifications of it) and assume
33  * contractual liability for the program to recipients of it, you agree
34  * to indemnify Electronic Arts for any liability that those contractual
35  * assumptions impose on Electronic Arts.
36  *
37  * You may not misrepresent the origins of this program; modified
38  * versions of the program must be marked as such and not identified as
39  * the original program.
40  *
41  * This disclaimer supplements the one included in the General Public
42  * License. TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS
43  * PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY
44  * OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK. THE ENTIRE RISK OF
45  * SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU. ELECTRONIC ARTS
46  * DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES,
47  * INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
48  * FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY
49  * RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING,
50  * USAGE, OR TRADE PRACTICE. ELECTRONIC ARTS DOES NOT WARRANT AGAINST
51  * INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL
52  * MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE
53  * UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE
54  * WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE
55  * CORRECTED. NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR
56  * ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SOME
57  * JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED
58  * WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
59  * CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY
60  * NOT APPLY TO YOU.
61  */
62 
79 
80 
81 #include "micropolis.h"
82 
83 
85 
86 
92 // City Classes:
93 // "VILLAGE", "TOWN", "CITY", "CAPITAL", "METROPOLIS", "MEGALOPOLIS"
94 
95 // City Levels:
96 // "Easy", "Medium", "Hard"
97 
98 // City Problems:
99 // "CRIME", "POLLUTION", "HOUSING COSTS", "TAXES",
100 // "TRAFFIC", "UNEMPLOYMENT", "FIRES"
101 
102 
104 
105 
111 {
112  //printf("cityEvaluation totalPop %d\n", totalPop);
113  if (totalPop > 0) {
114  short problemTable[PROBNUM]; // Score for each problem, higher the more severe the problem is.
115  for (int z = 0; z < PROBNUM; z++) {
116  problemTable[z] = 0;
117  }
118 
120  doPopNum();
121  doProblems(problemTable);
122  getScore(problemTable);
123  doVotes(); // How well is the mayor doing?
124  changeEval();
125  } else {
126  evalInit();
127  cityYes = 50; // No population => no voting. Let's say 50/50.
128  changeEval();
129  }
130 }
131 
132 
137 {
138  cityYes = 0;
139  cityPop = 0;
140  cityPopDelta = 0;
141  cityAssessedValue = 0;
143  cityScore = 500;
144  cityScoreDelta = 0;
145  for (int i = 0; i < PROBNUM; i++) {
146  problemVotes[i] = 0;
147  }
148  for (int i = 0; i < CVP_PROBLEM_COMPLAINTS; i++) {
150  }
151 }
152 
153 
160 {
161  Quad z;
162 
163  z = roadTotal * 5;
164  z += railTotal * 10;
165  z += policeStationPop * 1000;
166  z += fireStationPop * 1000;
167  z += hospitalPop * 400;
168  z += stadiumPop * 3000;
169  z += seaportPop * 5000;
170  z += airportPop * 10000;
171  z += coalPowerPop * 3000;
172  z += nuclearPowerPop * 6000;
173 
174  cityAssessedValue = z * 1000;
175 }
176 
177 
183 {
184  Quad oldCityPop = cityPop;
185 
187 
188  if (oldCityPop == -1) {
189  oldCityPop = cityPop;
190  }
191 
192  cityPopDelta = cityPop - oldCityPop;
194 }
195 
198 {
199  Quad pop = (resPop + (comPop + indPop) * 8L) * 20L;
200  return pop;
201 }
202 
203 
211 {
212  CityClass cityClassification = CC_VILLAGE;
213 
214  if (cityPopulation > 2000) {
215  cityClassification = CC_TOWN;
216  }
217  if (cityPopulation > 10000) {
218  cityClassification = CC_CITY;
219  }
220  if (cityPopulation > 50000) {
221  cityClassification = CC_CAPITAL;
222  }
223  if (cityPopulation > 100000) {
224  cityClassification = CC_METROPOLIS;
225  }
226  if (cityPopulation > 500000) {
227  cityClassification = CC_MEGALOPOLIS;
228  }
229 
230  return cityClassification;
231 }
232 
241 void Micropolis::doProblems(short problemTable[PROBNUM])
242 {
243  bool problemTaken[PROBNUM]; // Which problems are taken?
244 
245  for (int z = 0; z < PROBNUM; z++) {
246  problemTaken[z] = false;
247  problemTable[z] = 0;
248  }
249 
250  problemTable[CVP_CRIME] = crimeAverage; /* Crime */
251  problemTable[CVP_POLLUTION] = pollutionAverage; /* Pollution */
252  problemTable[CVP_HOUSING] = landValueAverage * 7 / 10; /* Housing */
253  problemTable[CVP_TAXES] = cityTax * 10; /* Taxes */
254  problemTable[CVP_TRAFFIC] = getTrafficAverage(); /* Traffic */
255  problemTable[CVP_UNEMPLOYMENT] = getUnemployment(); /* Unemployment */
256  problemTable[CVP_FIRE] = getFireSeverity(); /* Fire */
257  voteProblems(problemTable);
258 
259  for (int z = 0; z < CVP_PROBLEM_COMPLAINTS; z++) {
260  // Find biggest problem not taken yet
261  int maxVotes = 0;
262  int bestProblem = CVP_NUMPROBLEMS;
263  for (int i = 0; i < CVP_NUMPROBLEMS; i++) {
264  if ((problemVotes[i] > maxVotes) && (!problemTaken[i])) {
265  bestProblem = i;
266  maxVotes = problemVotes[i];
267  }
268  }
269 
270  // bestProblem == CVP_NUMPROBLEMS means no problem found
271  problemOrder[z] = bestProblem;
272  if (bestProblem < CVP_NUMPROBLEMS) {
273  problemTaken[bestProblem] = true;
274  }
275  // else: No problem found.
276  // Repeating the procedure will give the same result.
277  // Optimize by filling all remaining entries, and breaking out
278  }
279 }
280 
281 
288 void Micropolis::voteProblems(const short problemTable[PROBNUM])
289 {
290  for (int z = 0; z < PROBNUM; z++) {
291  problemVotes[z] = 0;
292  }
293 
294  int problem = 0; // Problem to vote for
295  int voteCount = 0; // Number of votes
296  int loopCount = 0; // Number of attempts
297  while (voteCount < 100 && loopCount < 600) {
298  if (getRandom(300) < problemTable[problem]) {
299  problemVotes[problem]++;
300  voteCount++;
301  }
302  problem++;
303  if (problem > PROBNUM) {
304  problem = 0;
305  }
306  loopCount++;
307  }
308 }
309 
310 
316 {
317  Quad trafficTotal;
318  short x, y, count;
319 
320  trafficTotal = 0;
321  count = 1;
322  for (x=0; x < WORLD_W; x += landValueMap.MAP_BLOCKSIZE) {
323  for (y=0; y < WORLD_H; y += landValueMap.MAP_BLOCKSIZE) {
324  if (landValueMap.worldGet(x, y) > 0) {
325  trafficTotal += trafficDensityMap.worldGet(x, y);
326  count++;
327  }
328  }
329  }
330 
331  trafficAverage = (short)((trafficTotal / count) * 2.4);
332 
333  return trafficAverage;
334 }
335 
336 
342 {
343  short b = (comPop + indPop) * 8;
344 
345  if (b == 0) {
346  return 0;
347  }
348 
349  // Ratio total people / working. At least 1.
350  float r = ((float)resPop) / b;
351 
352  b = (short)((r - 1) * 255); // (r - 1) is the fraction unemployed people
353  return min(b, (short)255);
354 }
355 
356 
362 {
363  return min(firePop * 5, 255);
364 }
365 
366 
371 void Micropolis::getScore(const short problemTable[PROBNUM])
372 {
373  int x, z;
374  short cityScoreLast;
375 
376  cityScoreLast = cityScore;
377  x = 0;
378 
379  for (z = 0; z < CVP_NUMPROBLEMS; z++) {
380  x += problemTable[z]; /* add 7 probs */
381  }
382 
386  x = x / 3; /* 7 + 2 average */
387  x = min(x, 256);
388 
389  z = clamp((256 - x) * 4, 0, 1000);
390 
391  if (resCap) {
392  z = (int)(z * .85);
393  }
394 
395  if (comCap) {
396  z = (int)(z * .85);
397  }
398 
399  if (indCap) {
400  z = (int)(z * .85);
401  }
402 
403  if (roadEffect < MAX_ROAD_EFFECT) {
405  }
406 
408  // 10.0001 = 10000.1 / 1000, 1/10.0001 is about 0.1
409  z = (int)(z * (0.9 + (policeEffect / (10.0001 * MAX_POLICE_STATION_EFFECT))));
410  }
411 
413  // 10.0001 = 10000.1 / 1000, 1/10.0001 is about 0.1
414  z = (int)(z * (0.9 + (fireEffect / (10.0001 * MAX_FIRE_STATION_EFFECT))));
415  }
416 
417  if (resValve < -1000) {
418  z = (int)(z * .85);
419  }
420 
421  if (comValve < -1000) {
422  z = (int)(z * .85);
423  }
424 
425  if (indValve < -1000) {
426  z = (int)(z * .85);
427  }
428 
429  float SM = 1.0;
430  if (cityPop == 0 || cityPopDelta == 0) {
431  SM = 1.0; // there is nobody or no migration happened
432 
433  } else if (cityPopDelta == cityPop) {
434  SM = 1.0; // city sprang into existence or doubled in size
435 
436  } else if (cityPopDelta > 0) {
437  SM = ((float)cityPopDelta / cityPop) + 1.0f;
438 
439  } else if (cityPopDelta < 0) {
440  SM = 0.95f + ((float)cityPopDelta / (cityPop - cityPopDelta));
441  }
442 
443  z = (int)(z * SM);
444  z = z - getFireSeverity() - cityTax; // dec score for fires and taxes
445 
446  float TM = unpoweredZoneCount + poweredZoneCount; // dec score for unpowered zones
447  if (TM > 0.0) {
448  z = (int)(z * (float)(poweredZoneCount / TM));
449  } else {
450  }
451 
452  z = clamp(z, 0, 1000);
453 
454  cityScore = (cityScore + z) / 2;
455 
456  cityScoreDelta = cityScore - cityScoreLast;
457 }
458 
459 
465 {
466  int z;
467 
468  cityYes = 0;
469 
470  for (z = 0; z < 100; z++) {
471  if (getRandom(1000) < cityScore) {
472  cityYes++;
473  }
474  }
475 }
476 
477 
480 {
481  // The user interface should pull these raw values out and format
482  // them. The simulator core used to format them and push them out,
483  // but the user interface should pull them out and format them
484  // itself.
485 
486  // City Evaluation ${FormatYear(currentYear())}
487  // Public Opinion
488  // Is the mayor doing a good job?
489  // Yes: ${FormatPercent(cityYes)}
490  // No: ${FormatPercent(100 - cityYes)}
491  // What are the worst problems?
492  // for i in range(0, CVP_PROBLEM_COMPLAINTS),
493  // while problemOrder[i] < CVP_NUMPROBLEMS:
494  // ${probStr[problemOrder[i]]}:
495  // ${FormatPercent(problemVotes[problemOrder[i]])}
496  // Statistics
497  // Population: ${FormatNumber(cityPop)}
498  // Net Migration: ${FormatNumber(cityPopDelta)} (last year)
499  // Assessed Value: ${FormatMoney(cityAssessedValue))
500  // Category: ${cityClassStr[cityClass]}
501  // Game Level: ${cityLevelStr[gameLevel]}
502 
503  callback->updateEvaluation(this, callbackVal);
504 }
505 
508 {
509  //printf("changeEval\n");
510  evalChanged = true;
511 }
512 
513 
516 {
517  //printf("scoreDoer evalChanged %d\n", evalChanged);
518  if (evalChanged) {
519  doScoreCard();
520  evalChanged = false;
521  }
522 }
523 
529 {
530  int i;
531  for (i = 0; i < CVP_PROBLEM_COMPLAINTS; i++) {
532  if (problemOrder[i] == CVP_NUMPROBLEMS) {
533  break;
534  }
535  }
536  return i;
537 }
538 
546 {
547  if (i < 0 || i >= CVP_PROBLEM_COMPLAINTS
548  || problemOrder[i] == CVP_NUMPROBLEMS) {
549  return -1;
550  } else {
551  return problemOrder[i];
552  }
553 }
554 
555 
563 {
564  if (i < 0 || i >= CVP_PROBLEM_COMPLAINTS
565  || problemOrder[i] == CVP_NUMPROBLEMS) {
566  return -1;
567  } else {
568  return problemVotes[problemOrder[i]];
569  }
570 }
571 
572 
DATA worldGet(int x, int y) const
Definition: map_type.h:316
const int MAP_BLOCKSIZE
Definition: map_type.h:121
Quad roadEffect
Definition: micropolis.h:1201
short problemVotes[PROBNUM]
Definition: micropolis.h:1559
void changeEval()
Definition: evaluate.cpp:507
short indPop
Definition: micropolis.h:996
short stadiumPop
Number of stadiums.
Definition: micropolis.h:1025
void evalInit()
Definition: evaluate.cpp:136
short getFireSeverity()
Definition: evaluate.cpp:361
short crimeAverage
Definition: micropolis.h:1063
Quad cityPopDelta
Definition: micropolis.h:1581
short poweredZoneCount
Number of powered tiles in all zone.
Definition: micropolis.h:2107
Quad policeEffect
Definition: micropolis.h:1206
CityClass getCityClass(Quad cityPop)
Definition: evaluate.cpp:210
Callback * callback
Definition: micropolis.h:954
void voteProblems(const short problemTable[PROBNUM])
Definition: evaluate.cpp:288
short unpoweredZoneCount
Number of unpowered tiles in all zones.
Definition: micropolis.h:2108
void scoreDoer()
Definition: evaluate.cpp:515
bool evalChanged
The evaluation window should be shown to the user.
Definition: micropolis.h:2350
short firePop
Definition: micropolis.h:975
void getScore(const short problemTable[PROBNUM])
Definition: evaluate.cpp:371
short resPop
Definition: micropolis.h:982
short getRandom(short range)
Definition: random.cpp:110
int countProblems()
Definition: evaluate.cpp:528
short getUnemployment()
Definition: evaluate.cpp:341
short problemOrder[CVP_PROBLEM_COMPLAINTS]
Definition: micropolis.h:1567
short cityScoreDelta
Definition: micropolis.h:1611
short getTrafficAverage()
Definition: evaluate.cpp:315
void doVotes()
Definition: evaluate.cpp:464
Quad getPopulation()
Definition: evaluate.cpp:197
short pollutionAverage
Definition: micropolis.h:1072
bool indCap
Block industrial growth.
Definition: micropolis.h:2095
Quad fireEffect
Definition: micropolis.h:1211
bool resCap
Block residential growth.
Definition: micropolis.h:2093
void doProblems(short problemTable[PROBNUM])
Definition: evaluate.cpp:241
short airportPop
Definition: micropolis.h:1055
short policeStationPop
Definition: micropolis.h:1030
int getProblemNumber(int i)
Definition: evaluate.cpp:545
void getAssessedValue()
Definition: evaluate.cpp:159
Quad cityPop
Definition: micropolis.h:1574
short totalPop
Definition: micropolis.h:1004
short cityYes
Definition: micropolis.h:1551
Quad cityAssessedValue
Definition: micropolis.h:1591
short landValueAverage
Definition: micropolis.h:1080
void doPopNum()
Definition: evaluate.cpp:182
short coalPowerPop
Definition: micropolis.h:1040
short hospitalPop
Number of hospitals.
Definition: micropolis.h:1022
short trafficAverage
Definition: micropolis.h:1618
void doScoreCard()
Definition: evaluate.cpp:479
int getProblemVotes(int i)
Definition: evaluate.cpp:562
MapByte2 trafficDensityMap
Traffic density map.
Definition: micropolis.h:1245
short cityScore
Definition: micropolis.h:1604
bool comCap
Block commercial growth.
Definition: micropolis.h:2094
CityClass cityClass
City class, affected by city population.
Definition: micropolis.h:1593
short nuclearPowerPop
Definition: micropolis.h:1045
short fireStationPop
Definition: micropolis.h:1035
short comPop
Definition: micropolis.h:989
MapByte2 landValueMap
Land value map.
Definition: micropolis.h:1247
short cityTax
Definition: micropolis.h:1224
short railTotal
Definition: micropolis.h:970
short seaportPop
Definition: micropolis.h:1050
short roadTotal
Definition: micropolis.h:963
void cityEvaluation()
Definition: evaluate.cpp:110
static const int WORLD_H
Definition: map_type.h:95
static const int WORLD_W
Definition: map_type.h:90
Header file for Micropolis game engine.
CityClass
Definition: micropolis.h:750
@ CC_CAPITAL
Capital, > 50000 citizens.
Definition: micropolis.h:754
@ CC_MEGALOPOLIS
Megalopolis, > 500000 citizens.
Definition: micropolis.h:756
@ CC_METROPOLIS
Metropolis, > 100000 citizens.
Definition: micropolis.h:755
@ CC_CITY
City, > 10000 citizens.
Definition: micropolis.h:753
@ CC_VILLAGE
Village.
Definition: micropolis.h:751
@ CC_TOWN
Town, > 2000 citizens.
Definition: micropolis.h:752
static const int MAX_FIRE_STATION_EFFECT
Definition: micropolis.h:263
static T min(const T a, const T b)
Definition: micropolis.h:783
@ CVP_NUMPROBLEMS
Number of problems.
Definition: micropolis.h:742
@ CVP_FIRE
Fire.
Definition: micropolis.h:740
@ CVP_POLLUTION
Pollution.
Definition: micropolis.h:735
@ CVP_TAXES
Taxes.
Definition: micropolis.h:737
@ CVP_HOUSING
Housing.
Definition: micropolis.h:736
@ CVP_UNEMPLOYMENT
Unemployment.
Definition: micropolis.h:739
@ CVP_TRAFFIC
Traffic.
Definition: micropolis.h:738
@ CVP_PROBLEM_COMPLAINTS
Number of problems to complain about.
Definition: micropolis.h:744
@ CVP_CRIME
Crime.
Definition: micropolis.h:734
static const int MAX_ROAD_EFFECT
Definition: micropolis.h:253
static const int MAX_POLICE_STATION_EFFECT
Definition: micropolis.h:258
static T clamp(const T val, const T lower, const T upper)
Definition: micropolis.h:808