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;
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
241void 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
288void 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
371void 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
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
short problemVotes[PROBNUM]
void changeEval()
Definition evaluate.cpp:507
short indPop
Definition micropolis.h:997
short stadiumPop
Number of stadiums.
void evalInit()
Definition evaluate.cpp:136
short getFireSeverity()
Definition evaluate.cpp:361
short crimeAverage
Quad cityPopDelta
short poweredZoneCount
Number of powered tiles in all zone.
Quad policeEffect
CityClass getCityClass(Quad cityPop)
Definition evaluate.cpp:210
Callback * callback
Definition micropolis.h:955
void voteProblems(const short problemTable[PROBNUM])
Definition evaluate.cpp:288
short unpoweredZoneCount
Number of unpowered tiles in all zones.
void scoreDoer()
Definition evaluate.cpp:515
bool evalChanged
The evaluation window should be shown to the user.
short firePop
Definition micropolis.h:976
void getScore(const short problemTable[PROBNUM])
Definition evaluate.cpp:371
short resPop
Definition micropolis.h:983
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]
short cityScoreDelta
short getTrafficAverage()
Definition evaluate.cpp:315
void doVotes()
Definition evaluate.cpp:464
Quad getPopulation()
Definition evaluate.cpp:197
short pollutionAverage
bool indCap
Block industrial growth.
Quad fireEffect
bool resCap
Block residential growth.
void doProblems(short problemTable[PROBNUM])
Definition evaluate.cpp:241
short airportPop
short policeStationPop
int getProblemNumber(int i)
Definition evaluate.cpp:545
void getAssessedValue()
Definition evaluate.cpp:159
short totalPop
short cityYes
Quad cityAssessedValue
short landValueAverage
void doPopNum()
Definition evaluate.cpp:182
short coalPowerPop
short hospitalPop
Number of hospitals.
short trafficAverage
void doScoreCard()
Definition evaluate.cpp:479
int getProblemVotes(int i)
Definition evaluate.cpp:562
MapByte2 trafficDensityMap
Traffic density map.
short cityScore
bool comCap
Block commercial growth.
CityClass cityClass
City class, affected by city population.
short nuclearPowerPop
short fireStationPop
short comPop
Definition micropolis.h:990
MapByte2 landValueMap
Land value map.
short cityTax
short railTotal
Definition micropolis.h:971
short seaportPop
short roadTotal
Definition micropolis.h:964
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:751
@ CC_CAPITAL
Capital, > 50000 citizens.
Definition micropolis.h:755
@ CC_MEGALOPOLIS
Megalopolis, > 500000 citizens.
Definition micropolis.h:757
@ CC_METROPOLIS
Metropolis, > 100000 citizens.
Definition micropolis.h:756
@ CC_CITY
City, > 10000 citizens.
Definition micropolis.h:754
@ CC_VILLAGE
Village.
Definition micropolis.h:752
@ CC_TOWN
Town, > 2000 citizens.
Definition micropolis.h:753
static const int MAX_FIRE_STATION_EFFECT
Definition micropolis.h:263
static T min(const T a, const T b)
Definition micropolis.h:784
@ CVP_NUMPROBLEMS
Number of problems.
Definition micropolis.h:743
@ CVP_FIRE
Fire.
Definition micropolis.h:741
@ CVP_POLLUTION
Pollution.
Definition micropolis.h:736
@ CVP_TAXES
Taxes.
Definition micropolis.h:738
@ CVP_HOUSING
Housing.
Definition micropolis.h:737
@ CVP_UNEMPLOYMENT
Unemployment.
Definition micropolis.h:740
@ CVP_TRAFFIC
Traffic.
Definition micropolis.h:739
@ CVP_PROBLEM_COMPLAINTS
Number of problems to complain about.
Definition micropolis.h:745
@ CVP_CRIME
Crime.
Definition micropolis.h:735
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:809