00001
00002
00003
00004
00005 #include <OBOX.H>
00006
00007 #include <OMATH.H>
00008 #include <OINFO.H>
00009 #include <OMISC.H>
00010 #include <ODEPT.H>
00011 #include <ODEPTRES.H>
00012 #include <OSCHLRES.H>
00013 #include <OPSCHOOL.H>
00014 #include <OPEERSCH.H>
00015 #include <OSYS.H>
00016
00017 #include <ALL.H>
00018 #include <STDIO.H>
00019
00020 #if(GAME_VERSION>=200)
00021
00022 #define MAX_TRADITION_COUNT 5
00023 #define MAX_NONTRA_COUNT 5
00024 #define MAX_MASTER_COUNT 3
00025 #define MAX_DOCTOR_COUNT 3
00026
00027 const RECORD_SEPARATOR_LEN = 2;
00028 static char *RECORD_SEPARATOR = "\r\n";
00029 const FIELD_SEPARATOR_LEN = 1;
00030 static char *FIELD_SEPARATOR = "\t";
00031
00032 static char *export_num(int value) {
00033 static char num_str[20];
00034 return itoa( value, num_str, 10 );
00035 }
00036
00037 static char *export_num(double value) {
00038 static char num_str[20];
00039 return gcvt( value, 7, num_str );
00040 }
00041
00042 static char *export_percent(double value) {
00043 static char num_str[20];
00044 return gcvt( value*0.01, 7, num_str );
00045 }
00046
00047 #define WRITE_FIELD_SEPARATOR(f) f->file_write(FIELD_SEPARATOR, FIELD_SEPARATOR_LEN)
00048 #define WRITE_STR_FIELD(f,s) { f->file_write(s, strlen(s)); }
00049 #define WRITE_NUM_FIELD(f,n) { char *s=export_num(n); f->file_write(s, strlen(s)); }
00050 #define WRITE_PERCENT_FIELD(f,n) { char *s=export_percent(n); f->file_write(s, strlen(s)); }
00051 #define WRITE_RECORD_SEPARATOR(f) f->file_write(RECORD_SEPARATOR, RECORD_SEPARATOR_LEN)
00052
00053
00054 short NONTRA_COUNT = 0;
00055 short MASTER_COUNT = 0;
00056 short DOCTOR_COUNT = 0;
00057 #endif
00058
00061 struct StudentStruct {
00062 int stu_recno;
00063 int dept_recno;
00064 char trimester_tag;
00065 };
00066
00069 class StuDynArray : public DynArray {
00070 public:
00071 StuDynArray() : DynArray(sizeof(StudentStruct), 200) {};
00072
00073 void deinit() {
00074 if( size()==0 )
00075 return;
00076
00077 for( int i=size() ; i>0 ; i-- ) {
00078
00079 linkout(i);
00080 }
00081
00082 zap();
00083 };
00084 };
00085
00086
00087
00088 static StuDynArray stuArr[MAX_STUDENT_LEVEL];
00089
00090
00092
00093
00094 generate_student_level_pct();
00095
00096
00097 generate_student_transition_prob_n_year_in_program();
00098
00099
00100 generate_student_gender_ethnic();
00101
00102
00103
00104
00105
00106
00107 generate_student_major_preference();
00108
00109
00110
00111
00112
00113 generate_student_adjust_pct_arrays();
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123 char studentLevel, yearInProgram, genderEthnicGroup, stuSeg, major;
00124 float talentArr[TALENT_VAR_COUNT];
00125 int i, finAid = 0, progressIndex = 50;
00126
00127 talentArr[0]=talentArr[1]=talentArr[2] = 0.5f;
00128
00129
00130 int stuCount = get_player_expected_student_count();
00131
00132
00133
00134 int sl_count=0;
00135
00136 #ifdef DEBUG
00137 int year1Count[MAX_STUDENT_LEVEL];
00138 memset( year1Count, 0, sizeof(year1Count) );
00139 #endif
00140
00141 for( i=stuCount; i>0 ; i-- ) {
00142
00143
00144
00145 #if(GAME_VERSION>=200)
00146 studentLevel = generate_student_random_get_group_index
00147 (student_level_pct, MAX_STUDENT_LEVEL-1);
00148 #else
00149 studentLevel = generate_student_random_get_group_index
00150 (student_level_pct, MAX_STUDENT_LEVEL);
00151 #endif
00152
00153 if ( studentLevel <= MASTER ) {
00154 yearInProgram = 1 + generate_student_random_get_group_index
00155 (year_in_program_pct[studentLevel], MAX_GRADUATE_YEARS+1);
00156 }
00157 else if ( studentLevel == DOCTOR ) {
00158
00159
00160 err_when(studentLevel-1 != SL_DOCTOR);
00161
00162 major = 1 + generate_student_random_get_group_index
00163 (adjusted_student_major_pref[SL_DOCTOR], department_array.department_count);
00164
00165 yearInProgram = 1 + generate_student_random_get_group_index
00166 (department_res[department_array[major]->department_id]->doctor_year_in_program_pct, MAX_GRADUATE_YEARS+1);
00167 }
00168 else if ( studentLevel == DISTANCE_LEARN ) {
00169 yearInProgram = 1 + generate_student_random_get_group_index
00170
00171 (year_in_program_pct[UG_NONTRADITION], MAX_GRADUATE_YEARS+1);
00172 }
00173 else
00174 err_here();
00175
00176 if(yearInProgram==1)
00177 sl_count++;
00178
00179
00180
00181 genderEthnicGroup = generate_student_random_get_group_index
00182 (student_gender_pct[studentLevel], GENDER_ETHNIC_TYPE_COUNT);
00183
00184
00185
00186 if ( yearInProgram > 1 ||
00187 ( !is_ug_group(studentLevel) ) ) {
00188 if ( studentLevel != DOCTOR ) {
00189 short sl;
00190 if ( studentLevel == DISTANCE_LEARN )
00191 sl = SL_UG;
00192 else if ( studentLevel > UG_TRADITION )
00193 sl = studentLevel - 1;
00194 else
00195 sl = SL_UG;
00196
00197 err_when(MASTER != UG_TRADITION + 2);
00198
00199
00200 major = 1 + generate_student_random_get_group_index
00201
00202 (adjusted_student_major_pref[sl], department_array.department_count);
00203 }
00204 }
00205 else if ( yearInProgram == 1 ) {
00206
00207 major = 0;
00208 }
00209 else
00210 err_here();
00211
00212
00213
00214 if ( studentLevel == UG_TRADITION ) {
00215 stuSeg = m.random(STUDENT_SEGMENT_COUNT);
00216 }
00217 else {
00218 stuSeg = -1;
00219 }
00220
00221
00222
00223
00224
00225 if ( yearInProgram > 1 ) {
00226
00227
00228 enroll_res.calc_a_talent(talentArr, studentLevel, genderEthnicGroup, stuSeg);
00229
00230 int stuRecno=0;
00231 if ( major )
00232 stuRecno = department_array[major]->student_array.add( studentLevel, yearInProgram,
00233 genderEthnicGroup, stuSeg, major, finAid, talentArr );
00234 else
00235 err_here();
00236
00237
00238
00239
00240
00241 Student* stuPtr = department_array[major]->student_array[stuRecno];
00242 StudentStruct stuStruct;
00243
00244 stuStruct.stu_recno = stuRecno;
00245 stuStruct.dept_recno = major;
00246 stuStruct.trimester_tag = -1;
00247
00248
00249 stuArr[studentLevel].linkin(&stuStruct);
00250
00251
00252
00253
00254
00255 }
00256 #ifdef DEBUG
00257 else {
00258 ++year1Count[studentLevel];
00259 }
00260 #endif
00261 }
00262
00263 #if(GAME_VERSION>=200)
00264 if ( sys.debug_session ) {
00265 do {
00266 Department* deptPtr = department_array[m.random(10)+1];
00267
00268 int stdRecno = m.random(deptPtr->student_array.size())+1;
00269
00270 Student* stdPtr = deptPtr->student_array[stdRecno];
00271
00272 if ( stdPtr->audit_flag )
00273 continue;
00274
00275 switch ( stdPtr->student_level ) {
00276 case UG_TRADITION: continue;
00277 break;
00278 case UG_NONTRADITION: if ( NONTRA_COUNT >= MAX_NONTRA_COUNT )
00279 continue;
00280 NONTRA_COUNT++;
00281 break;
00282 case MASTER: if ( MASTER_COUNT >= MAX_MASTER_COUNT )
00283 continue;
00284 MASTER_COUNT++;
00285 break;
00286 case DOCTOR: if ( DOCTOR_COUNT >= MAX_DOCTOR_COUNT )
00287 continue;
00288 DOCTOR_COUNT++;
00289 break;
00290 }
00291
00292 stdPtr->old_student_recno = stdRecno;
00293
00294 stdPtr->audit_flag = 1;
00295
00296 File file;
00297
00298 char fileName[123];
00299
00300 switch( stdPtr->student_level ) {
00301 case UG_NONTRADITION: strcpy( fileName, "NONTRADITION" );
00302 break;
00303 case MASTER: strcpy( fileName, "MASTER" );
00304 break;
00305 case DOCTOR: strcpy( fileName, "DOCTOR" );
00306 break;
00307 }
00308
00309 strcat( fileName, m.format(stdPtr->old_student_recno) );
00310 strcat( fileName, ".txt" );
00311
00312 file.file_create(fileName);
00313
00314 WRITE_STR_FIELD( (&file), "Cohort" );
00315 WRITE_FIELD_SEPARATOR( (&file) );
00316 WRITE_STR_FIELD( (&file), "Trimester" );
00317 WRITE_FIELD_SEPARATOR( (&file) );
00318 WRITE_STR_FIELD( (&file), "ID" );
00319 WRITE_FIELD_SEPARATOR( (&file) );
00320 WRITE_STR_FIELD( (&file), "Variable" );
00321 WRITE_FIELD_SEPARATOR( (&file) );
00322 WRITE_STR_FIELD( (&file), "Trimester" );
00323 WRITE_RECORD_SEPARATOR( (&file) );
00324
00325 for ( int i=0; i<4; i++ ) {
00326 WRITE_NUM_FIELD( (&file), -1 );
00327 WRITE_FIELD_SEPARATOR( (&file) );
00328 WRITE_STR_FIELD( (&file), "A" );
00329 WRITE_FIELD_SEPARATOR( (&file) );
00330 WRITE_FIELD_SEPARATOR( (&file) );
00331 WRITE_STR_FIELD( (&file), "S" );
00332 WRITE_FIELD_SEPARATOR( (&file) );
00333
00334 switch (i) {
00335 case 0: WRITE_STR_FIELD( (&file), "Courses" );
00336 WRITE_FIELD_SEPARATOR( (&file) );
00337 WRITE_FIELD_SEPARATOR( (&file) );
00338 WRITE_NUM_FIELD( (&file), stdPtr->course_per_trimester[0] );
00339 WRITE_NUM_FIELD( (&file), stdPtr->course_per_trimester[1] );
00340 WRITE_NUM_FIELD( (&file), stdPtr->course_per_trimester[2] );
00341 break;
00342
00343 case 1: WRITE_STR_FIELD( (&file), "Status" );
00344 WRITE_FIELD_SEPARATOR( (&file) );
00345 WRITE_FIELD_SEPARATOR( (&file) );
00346 if ( stdPtr->department_recno ) {
00347 WRITE_STR_FIELD( (&file), department_res[department_array[stdPtr->department_recno]->department_id]->name );
00348 }
00349 else
00350 WRITE_STR_FIELD( (&file), "Undec" );
00351 break;
00352
00353 case 2: WRITE_STR_FIELD( (&file), "AcadTalent" );
00354 WRITE_FIELD_SEPARATOR( (&file) );
00355 WRITE_NUM_FIELD( (&file), stdPtr->talent_academic );
00356 break;
00357 case 3: WRITE_STR_FIELD( (&file), "GenEnth" );
00358 WRITE_FIELD_SEPARATOR( (&file) );
00359 WRITE_FIELD_SEPARATOR( (&file) );
00360 switch( stdPtr->gender_ethnic_group ) {
00361 case NONMINORITY_MALE: WRITE_STR_FIELD( (&file), "NM" ); break;
00362 case NONMINORITY_FEMALE: WRITE_STR_FIELD( (&file), "NF" ); break;
00363 case MINORITY_MALE: WRITE_STR_FIELD( (&file), "MM" ); break;
00364 case MINORITY_FEMALE: WRITE_STR_FIELD( (&file), "MF" ); break;
00365 }
00366 break;
00367 }
00368 WRITE_RECORD_SEPARATOR( (&file) );
00369 }
00370
00371 file.file_close();
00372 } while ((NONTRA_COUNT != MAX_NONTRA_COUNT ) || (MASTER_COUNT != MAX_MASTER_COUNT) || (DOCTOR_COUNT != MAX_DOCTOR_COUNT));
00373 }
00374 #endif
00375
00376
00377 generate_student_init_course(progressIndex);
00378
00379 for (char sl=0; sl<MAX_STUDENT_LEVEL; sl++)
00380 stuArr[sl].deinit();
00381
00382 }
00383
00384
00385
00386
00390
00391 int PlayerSchool::get_player_expected_student_count() {
00392 const int remap[INPUT_OPTION_COUNT] = {
00393 2000, 6000, 10000
00394 };
00395
00396
00397 err_when(student_count < 0 || student_count >= INPUT_OPTION_COUNT);
00398
00399 return remap[student_count];
00400
00401 return student_count;
00402 }
00403
00404 #if(GAME_VERSION>=200)
00405 int PlayerSchool::get_player_expected_sponsored_research() {
00406 switch (sponsored_research_intensity) {
00407 case 0: return 1;
00408 case 5: return 2;
00409 case 10: return 4;
00410 default:
00411 err_here();
00412 return 1;
00413 }
00414 }
00415 #endif
00416
00417 void PlayerSchool::generate_student_level_pct() {
00418 PeerSchool *playerEx = school_res.player_peer_school;
00419 int studentCount=0, i;
00420
00421 err_when(UG_TRADITION != 0 || UG_NONTRADITION != 1);
00422
00423 float sl2Multiplier[3] = { 1.5f, 1.0f, 0.5f };
00424 err_when(URBAN != 0);
00425
00426 int realStuCount = get_player_expected_student_count();
00427
00428 student_level_pct[UG_TRADITION] = playerEx->full_time_undergrad;
00429
00430 student_level_pct[UG_NONTRADITION] = playerEx->part_time_undergrad * sl2Multiplier[player_school.campus_environment] * player_school.parttime_undergrad_percent / 100;
00431
00432 student_level_pct[DISTANCE_LEARN] = (float) ( realStuCount * sl5_student_percent / 100);
00433
00434 int gradStudCount = realStuCount * graduate_student_percent / 100;
00435
00436 student_level_pct[DOCTOR] = gradStudCount * player_school.doctoral_program_intensity / 100;
00437 student_level_pct[MASTER] = gradStudCount - student_level_pct[DOCTOR];
00438
00439
00440
00441 for (i=0; i<MAX_STUDENT_LEVEL; i++)
00442 studentCount += (int) student_level_pct[i];
00443
00444
00445
00446 float scaleFactor = float(realStuCount) / studentCount;
00447
00448 for (i=0; i<MAX_STUDENT_LEVEL; i++) {
00449 student_level_pct[i]
00450 = (student_level_pct[i] * scaleFactor) / realStuCount;
00451 }
00452 }
00453
00454
00455
00456
00466
00467 PeerSchool *playerEx = school_res.player_peer_school;
00468 int yr, sl, i;
00469
00470
00471
00472
00473
00474
00475 const float dropouts_fraction[MASTER_ARRAY_SIZE][MAX_GRADUATE_YEARS] = {
00476 { 0.29f, 0.19f, 0.26f, 0.16f, 0.07f, 0.02f, 0.01f, 0.00f },
00477 { 0.25f, 0.20f, 0.15f, 0.10f, 0.08f, 0.08f, 0.07f, 0.07f },
00478 { 0.70f, 0.30f, 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.00f }
00479
00480 };
00481
00482 const float graduates_fraction[MASTER_ARRAY_SIZE][MAX_GRADUATE_YEARS] = {
00483 { 0.00f, 0.00f, 0.06f, 0.53f, 0.31f, 0.08f, 0.02f, 0.00f },
00484 { 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.10f, 0.30f, 0.50f },
00485 { 0.95f, 0.05f, 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.00f }
00486 };
00487
00488 err_when(UG_TRADITION!=0);
00489 err_when(MASTER!=2);
00490
00491
00492
00493 float fractionWhoGradOnTime[UG_NONTRADITION+1];
00494 float gradAnytimePct[MASTER_ARRAY_SIZE];
00495
00496 memset(fractionWhoGradOnTime, 0, sizeof(fractionWhoGradOnTime));
00497
00498 for (i=0; i<MAX_GRADUATE_YEARS; i++)
00499 fractionWhoGradOnTime[UG_TRADITION] += graduates_fraction[UG_TRADITION][i];
00500
00501 for (i=0; i<MAX_GRADUATE_YEARS; i++)
00502 fractionWhoGradOnTime[UG_NONTRADITION] += graduates_fraction[UG_NONTRADITION][i];
00503
00504 for (sl= 0; sl<=UG_NONTRADITION; sl++) {
00505 gradAnytimePct[sl]
00506 = playerEx->target_grad_rate_sl[sl] / 100.0f
00507 + ( 1-playerEx->target_grad_rate_sl[sl] / 100.0f )
00508 * ( 1-fractionWhoGradOnTime[sl] );
00509 }
00510
00511 gradAnytimePct[MASTER] = playerEx->target_grad_rate_sl[MASTER] / 100.0f;
00512
00513
00514
00515 float fractionSurvivors[MAX_GRADUATE_YEARS+1], popDivisor[MASTER_ARRAY_SIZE];
00516 float gradTransProb[MASTER_ARRAY_SIZE][MAX_GRADUATE_YEARS];
00517
00518 for (sl=0; sl<MASTER_ARRAY_SIZE; sl++) {
00519 for (yr=0; yr<MAX_GRADUATE_YEARS; yr++) {
00520 if ( yr > 0 ) {
00521 fractionSurvivors[yr] = fractionSurvivors[yr-1] * (1.0f - gradTransProb[sl][yr-1] - dropout_trans_prob[sl][yr-1]);
00522 popDivisor[sl] += fractionSurvivors[yr];
00523 }
00524 else {
00525 fractionSurvivors[yr] = 1.0f;
00526 popDivisor[sl] = fractionSurvivors[yr];
00527 }
00528
00529 #if(GAME_VERSION>=200)
00530
00531 dropout_trans_prob[sl][yr] = math.safe_divide( dropouts_fraction[sl][yr] * ( 1.0f - gradAnytimePct[sl] ), fractionSurvivors[yr] );
00532
00533 gradTransProb[sl][yr] = math.safe_divide( graduates_fraction[sl][yr] * gradAnytimePct[sl], fractionSurvivors[yr] );
00534 #else
00535 dropout_trans_prob[sl][yr] = dropouts_fraction[sl][yr] * ( 1.0f - gradAnytimePct[sl] ) / fractionSurvivors[yr];
00536
00537 gradTransProb[sl][yr] = graduates_fraction[sl][yr] * gradAnytimePct[sl] / fractionSurvivors[yr];
00538 #endif
00539 }
00540
00541
00542 fractionSurvivors[yr] = fractionSurvivors[yr-1] * (1.0f - gradTransProb[sl][yr-1] - dropout_trans_prob[sl][yr-1]);
00543 popDivisor[sl] += fractionSurvivors[yr];
00544
00545 for (yr=0; yr<MAX_GRADUATE_YEARS+1; yr++) {
00546 #if(GAME_VERSION>=200)
00547 year_in_program_pct[sl][yr] = math.safe_divide( fractionSurvivors[yr], popDivisor[sl] );
00548 #else
00549 year_in_program_pct[sl][yr] = fractionSurvivors[yr] / popDivisor[sl];
00550 #endif
00551
00552 if(year_in_program_pct[sl][yr]<=0)
00553 year_in_program_pct[sl][yr]=0;
00554 }
00555 }
00556
00557 memcpy(grad_trans_prob, gradTransProb, sizeof(gradTransProb));
00558
00559
00560
00561
00562 short deptCount = department_res.department_count;
00563 for( i=1 ; i<=deptCount ; i++ ) {
00564 DepartmentInfo *deptInfo = department_res[i];
00565 deptInfo->generate_student_transition_prob_n_year_in_program_doctor();
00566 }
00567
00568
00569 }
00570
00571
00572
00573
00577
00578
00579
00580
00581 short sl = DOCTOR;
00582 short yr;
00583
00584 PeerSchool *playerEx = school_res.player_peer_school;
00585 float targetSchoolGradRate = playerEx->target_grad_rate_sl[sl] / 100.0f;
00586 float avgTimeToDegree = playerEx->doc_time_to_degree;
00587
00588
00589
00590
00591
00592 float avgTimeToDropout = 0.5f * avgTimeToDegree;
00593
00594
00595
00596 #define MAX_GRADUATE_RATE 0.8f
00597
00598 DepartmentInfo* deptInfo = this;
00599
00600 float cummGradRate = targetSchoolGradRate * deptInfo->doctoral_grad_rate_multiplier;
00601 if ( cummGradRate > MAX_GRADUATE_RATE )
00602 cummGradRate = MAX_GRADUATE_RATE;
00603
00604 float aveTimeToDropout = avgTimeToDropout * deptInfo->doctoral_time_to_dropout_multiplier;
00605 float aveTimeToDegree = avgTimeToDegree * deptInfo->doctoral_time_to_degree_multiplier;
00606
00607
00608
00609 float graduateFraction, dropoutFraction;
00610 float fractionSurvivors[MAX_GRADUATE_YEARS], popDivisor;
00611
00612 for (yr=0; yr<MAX_GRADUATE_YEARS; yr++) {
00613 if ( yr > 0 ) {
00614 fractionSurvivors[yr] = fractionSurvivors[yr-1] * (1.0f - doctor_dropout_trans_prob[yr-1] - doctor_graduate_trans_prob[yr-1]);
00615 popDivisor += fractionSurvivors[yr];
00616 }
00617 else {
00618 fractionSurvivors[yr] = 1.0f;
00619 popDivisor = fractionSurvivors[yr];
00620 }
00621
00622
00623 yr++;
00624 dropoutFraction
00625 = float( exp((1-yr)/aveTimeToDropout) - exp(-yr/aveTimeToDropout));
00626 graduateFraction
00627 = float( exp((3-yr)/(aveTimeToDegree-2)) - exp((2-yr)/(aveTimeToDegree-2)));
00628 yr--;
00629
00630
00631
00632 doctor_dropout_trans_prob[yr] = dropoutFraction*(1-cummGradRate)/fractionSurvivors[yr];
00633
00634 if ( yr==0 || yr==1 )
00635 doctor_graduate_trans_prob[yr] = 0.0f;
00636 else
00637 doctor_graduate_trans_prob[yr] = graduateFraction*cummGradRate/fractionSurvivors[yr];
00638 }
00639
00640 fractionSurvivors[yr] = fractionSurvivors[yr-1] * (1.0f - doctor_dropout_trans_prob[yr-1] - doctor_graduate_trans_prob[yr-1]);
00641 popDivisor += fractionSurvivors[yr];
00642
00643 for (yr=0; yr<MAX_GRADUATE_YEARS+1; yr++) {
00644 doctor_year_in_program_pct[yr] = fractionSurvivors[yr] / popDivisor;
00645 }
00646 }
00647
00648
00649
00650
00654
00655
00656
00657 PeerSchool *playerEx = school_res.player_peer_school;
00658
00659 for ( int sl=0; sl<MAX_STUDENT_LEVEL; sl++ ) {
00660
00661
00662 float femalePercent = playerEx->percent_female_sl[sl] / 100.0f;
00663 float minorityPercent = playerEx->percent_minority_sl[sl] / 100.0f;
00664
00665
00666
00667 if ( info.year_passed == 1 && player_school.scenario_id == SCN_STUDENT_DIVERSITY ) {
00668 minorityPercent *= 0.571f;
00669 }
00670
00671
00672
00673 student_gender_pct[sl][MINORITY_FEMALE] = femalePercent*minorityPercent;
00674 student_gender_pct[sl][NONMINORITY_FEMALE] = femalePercent*(1.0f - minorityPercent);
00675 student_gender_pct[sl][MINORITY_MALE] = (1.0f - femalePercent)*minorityPercent;
00676 student_gender_pct[sl][NONMINORITY_MALE] = (1.0f - femalePercent)*(1.0f - minorityPercent);
00677 }
00678 }
00679
00680
00681
00682
00686
00687 short i, sl, deptCount, deptId;
00688 DepartmentInfo *deptInfo;
00689
00690 deptCount = department_res.department_count;
00691 for( i=1 ; i<=deptCount ; i++ ) {
00692 deptInfo = department_res[i];
00693 deptInfo->generate_student_major_preference();
00694 }
00695
00696
00697
00698
00699
00700
00701
00702 deptCount = department_array.department_count;
00703 float totalPctIncludedDept = 0.0f;
00704
00705 err_when(!deptCount);
00706 memset(adjusted_student_major_pref, 0, sizeof(adjusted_student_major_pref));
00707
00708 for (sl=0; sl<MAX_STUDENT_LEVEL_INI; sl++) {
00709 totalPctIncludedDept = 0.0f;
00710
00711 for (i=1; i<=deptCount; i++) {
00712 deptId = department_array[i]->department_id;
00713 deptInfo = department_res[deptId];
00714 totalPctIncludedDept += deptInfo->student_major_pref[sl];
00715 }
00716
00717 for (i=1; i<=deptCount; i++) {
00718 deptId = department_array[i]->department_id;
00719 deptInfo = department_res[deptId];
00720
00721 adjusted_student_major_pref[sl][i-1] = math.safe_divide(deptInfo->student_major_pref[sl], totalPctIncludedDept);
00722
00723
00724 }
00725
00726
00727 float minPct = 1.0f / deptCount;
00728 totalPctIncludedDept = 0;
00729
00730 for (i=1; i<=deptCount; i++) {
00731
00732 if ( adjusted_student_major_pref[sl][i-1] < minPct )
00733
00734 adjusted_student_major_pref[sl][i-1] += 0.03f;
00735
00736 totalPctIncludedDept += adjusted_student_major_pref[sl][i-1];
00737 }
00738
00739 for (i=1; i<=deptCount; i++)
00740 adjusted_student_major_pref[sl][i-1] /= totalPctIncludedDept;
00741
00742
00743 }
00744 }
00745
00746
00747
00748
00752
00753 short sl;
00754 PeerSchool *playerEx = school_res.player_peer_school;
00755
00756 for (sl=0; sl<MAX_STUDENT_LEVEL_INI; sl++) {
00757
00758
00759
00760 student_major_pref[sl]
00761 = playerEx->student_ifield_pct[sl][iped_field]
00762 * field_fraction_pct[sl];
00763 }
00764
00765
00766 }
00767
00768
00769
00770
00773
00774 int sl, i;
00775
00776 generate_student_adjust_pct_array
00777 (student_level_pct, MAX_STUDENT_LEVEL);
00778
00779 for (sl=0; sl<MASTER_ARRAY_SIZE; sl++) {
00780 generate_student_adjust_pct_array
00781 (year_in_program_pct[sl], MAX_GRADUATE_YEARS+1);
00782 }
00783
00784 short deptCount = department_res.department_count;
00785 for( i=1 ; i<=deptCount ; i++ ) {
00786 generate_student_adjust_pct_array
00787 (department_res[i]->doctor_year_in_program_pct, MAX_GRADUATE_YEARS+1);
00788 }
00789
00790 for (sl=0; sl<MAX_STUDENT_LEVEL; sl++) {
00791 generate_student_adjust_pct_array
00792 (student_gender_pct[sl], GENDER_ETHNIC_TYPE_COUNT);
00793 }
00794
00795 for (sl=0; sl<MAX_STUDENT_LEVEL_INI; sl++) {
00796 generate_student_adjust_pct_array
00797 (adjusted_student_major_pref[sl], department_array.department_count);
00798 }
00799 }
00800
00801 void PlayerSchool::generate_student_adjust_pct_array(float *arr, int size) {
00802 int i;
00803 for (i=1; i<size; i++)
00804 arr[i] += arr[i-1];
00805
00806 if ( arr[size-1] > 0.95)
00807 arr[size-1] = 1.0f;
00808 else {
00809 if (arr[0] != 0 )
00810 err_here();
00811 }
00812 }
00813
00814 void PlayerSchool::generate_student_readjust_pct_array(float *arr, int size) {
00815 int i;
00816 for (i=size-1; i>0; i--)
00817 arr[i] -= arr[i-1];
00818
00819 err_when(arr[0]<0);
00820 }
00821
00822
00823
00824
00825
00826
00827
00828
00829 char PlayerSchool::generate_student_random_get_group_index(float *arr, int size) {
00830 const int randomPrecesion = 10000;
00831 float rand = float(m.random(randomPrecesion+1)) / randomPrecesion;
00832
00833 err_when(size >127);
00834
00835 for ( int i=0; i<size; i++ ) {
00836 if ( rand <= arr[i] )
00837 return (char) i;
00838 }
00839 return 0;
00840 }
00841
00842
00843
00844
00845
00846
00847
00848
00849 int PlayerSchool::get_random_major(char sl) {
00850 if ( sl == DISTANCE_LEARN)
00851 sl = UG_TRADITION;
00852 if ( sl >= UG_NONTRADITION )
00853 sl--;
00854
00855 err_when(sl<0 || sl>= MAX_STUDENT_LEVEL_INI);
00856
00857 int returnValue = 1 + generate_student_random_get_group_index( adjusted_student_major_pref[sl], department_array.department_count );
00858
00859 #if(GAME_VERSION>=200)
00860 if ( returnValue > department_array.size() )
00861 returnValue = department_array.size();
00862 #endif
00863
00864 return returnValue;
00865
00866 }
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902 static char cur_student_level_for_sorting = 0;
00903
00904
00908
00909
00910
00911
00912 StudentStruct* stuStrPtrA, *stuStrPtrB;
00913 Student* stuPtrA, *stuPtrB;
00914
00915 stuStrPtrA = (StudentStruct *) stuArr[cur_student_level_for_sorting].get(*((short*)a));
00916 stuStrPtrB = (StudentStruct *) stuArr[cur_student_level_for_sorting].get(*((short*)b));
00917
00918 float rc = float(stuStrPtrA->trimester_tag - stuStrPtrB->trimester_tag);
00919
00920 if( rc > 0 )
00921 return 1;
00922 else if( rc < 0 )
00923 return -1;
00924
00925 stuPtrA = department_array[stuStrPtrA->dept_recno]->student_array[stuStrPtrA->stu_recno];
00926 stuPtrB = department_array[stuStrPtrB->dept_recno]->student_array[stuStrPtrB->stu_recno];
00927
00928 float valueA = stuPtrA->talent_academic;
00929 float valueB = stuPtrB->talent_academic;
00930
00931 rc = valueA - valueB;
00932
00933 if( rc > 0 )
00934 return 1;
00935 else if( rc < 0 )
00936 return -1;
00937 else
00938 return 0;
00939 }
00940
00941
00942
00943
00948
00949 for SL-1,2,4,5
00950 {
00951 set tag = 0
00952
00953 for eachTriGroup (note: i.e. there're (8-2 = 6) TriGroups for SL-1)
00954 {
00955 generate sims for this triGroup
00956 assign the current tag to these sims
00957 for each sim generated for this triGroup AND sims created SO FAR
00958 {
00959 run A-2
00960 }
00961 increment tag!!!
00962 }
00963
00964 run B for SL-1,2,3,4,5
00965 }
00966
00967 */
00968
00969 void PlayerSchool::generate_student_init_course(int progressIndex) {
00970 int try_to_count = 0;
00971 const char norm_ft_trimesters[MAX_STUDENT_LEVEL] = { 8,8,2,4,8 };
00972
00973 const char no_of_time_sel_cour[MAX_STUDENT_LEVEL] = {
00974 2,2,1,1,2
00975 };
00976
00977 int i;
00978
00979 StudentStruct* stuStrPtr;
00980 Student* stuPtr;
00981
00982
00983
00984 int stuCount = 0;
00985
00986 for( i=0 ; i<MAX_STUDENT_LEVEL ; i++ ) {
00987 if( stuArr[i].size() > stuCount )
00988 stuCount = stuArr[i].size();
00989 }
00990
00991 err_when( stuCount <= 0 );
00992 err_when( stuCount > 10000000 );
00993
00994
00995
00996 short* stuSortArray = (short*) mem_add( stuCount * sizeof(short) );
00997
00998 for ( char sl=0; sl<MAX_STUDENT_LEVEL; sl++ ) {
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014
01015
01016
01017
01018
01019
01020
01021
01022
01023
01024
01025 int tag = 1;
01026 int time_in_school;
01027 int stuCountThisLevel = stuArr[sl].size();
01028
01029 int stuCountPerTrimester = stuCountThisLevel / norm_ft_trimesters[sl];
01030
01031 #ifdef DEBUG
01032 int studentYearCount[MAX_GRADUATE_YEARS+1];
01033 memset( studentYearCount, 0, sizeof(studentYearCount) );
01034 int studentCredit[32+1];
01035 memset( studentCredit, 0, sizeof(studentCredit) );
01036 #endif
01037
01038 for ( i=1; i<=stuCountThisLevel; i++ ) {
01039
01040 stuStrPtr = (StudentStruct *) stuArr[sl].get(i);
01041 stuPtr = department_array[stuStrPtr->dept_recno]->student_array[stuStrPtr->stu_recno];
01042
01043 err_when(stuPtr->year_in_program == 1);
01044 time_in_school = stuPtr->year_in_program-1;
01045
01046 #if(GAME_VERSION>=200)
01047
01048
01049 #else
01050 if(sl==UG_TRADITION && time_in_school>5)
01051 time_in_school=3;
01052 #endif
01053
01054 #ifdef DEBUG
01055 if( time_in_school > MAX_GRADUATE_YEARS )
01056 studentYearCount[MAX_GRADUATE_YEARS]++;
01057 else if( time_in_school >= 0 )
01058 studentYearCount[time_in_school]++;
01059 #endif
01060
01061 for ( int t=0; t<no_of_time_sel_cour[sl]*time_in_school; t++ ) {
01062 #if(GAME_VERSION>=200)
01063 if ( stuPtr->audit_flag ) {
01064 File file;
01065
01066 char fileName[123];
01067
01068 switch( stuPtr->student_level ) {
01069 case UG_TRADITION: strcpy( fileName, "TRADITION" );
01070 break;
01071 case UG_NONTRADITION: strcpy( fileName, "NONTRADITION" );
01072 break;
01073 case MASTER: strcpy( fileName, "MASTER" );
01074 break;
01075 case DOCTOR: strcpy( fileName, "DOCTOR" );
01076 break;
01077 }
01078
01079 strcat( fileName, m.format(stuPtr->old_student_recno) );
01080 strcat( fileName, ".txt" );
01081
01082 file.file_append( fileName );
01083 file.file_seek(0, FILE_END);
01084
01085 char textDisplay[128];
01086 sprintf( textDisplay, "****** This is the No.%d trimester in the history ******", t );
01087 WRITE_STR_FIELD( (&file), textDisplay );
01088
01089 WRITE_RECORD_SEPARATOR( (&file) );
01090
01091 file.file_close();
01092 }
01093 #endif
01094
01095 #if(GAME_VERSION>=200)
01096 stuPtr->select_course(1, 1);
01097 #else
01098 stuPtr->select_course(1);
01099 #endif
01100 }
01101
01102
01103
01104
01105 #ifdef DEBUG
01106 if( stuPtr->total_course_all >= 32 )
01107 ++studentCredit[32];
01108 else if( stuPtr->total_course_all >= 0 )
01109 ++studentCredit[stuPtr->total_course_all];
01110 #endif
01111 tag++;
01112 }
01113
01114
01115
01116 int t = norm_ft_trimesters[sl]-2;
01117 int tmpBound = stuCountPerTrimester * t;
01118
01119 for ( i=1; i<=stuCountThisLevel; i++ ) {
01120 stuStrPtr = (StudentStruct *) stuArr[sl].get(i);
01121 stuPtr = department_array[stuStrPtr->dept_recno]->student_array[stuStrPtr->stu_recno];
01122
01123 if ( i > tmpBound )
01124 stuStrPtr->trimester_tag = tag;
01125 try_to_count++;
01126 #if(GAME_VERSION>=200)
01127 if ( stuPtr->audit_flag ) {
01128 File file;
01129
01130 char fileName[123];
01131
01132 switch( stuPtr->student_level ) {
01133 case UG_TRADITION: strcpy( fileName, "TRADITION" );
01134 break;
01135 case UG_NONTRADITION: strcpy( fileName, "NONTRADITION" );
01136 break;
01137 case MASTER: strcpy( fileName, "MASTER" );
01138 break;
01139 case DOCTOR: strcpy( fileName, "DOCTOR" );
01140 break;
01141 }
01142
01143 strcat( fileName, m.format(stuPtr->old_student_recno) );
01144 strcat( fileName, ".txt" );
01145
01146 file.file_append( fileName );
01147 file.file_seek(0, FILE_END);
01148
01149 WRITE_STR_FIELD( (&file), "********** It is the start of the prerun year **********" );
01150
01151 WRITE_RECORD_SEPARATOR( (&file) );
01152
01153 file.file_close();
01154 }
01155 #endif
01156 stuPtr->select_course(1);
01157 }
01158
01159
01160
01161 for( i=1; i<=stuCountThisLevel; i++ )
01162 stuSortArray[i-1] = i;
01163
01164 cur_student_level_for_sorting = sl;
01165 qsort( stuSortArray, stuCountThisLevel, sizeof(stuSortArray[0]), sort_stu_talent_function );
01166
01167
01168
01169 float *yearInProgramPctArr;
01170
01171 if ( sl <= MASTER ) {
01172 yearInProgramPctArr = year_in_program_pct[sl];
01173 }
01174 else if ( sl == DOCTOR ) {
01175
01176
01177
01178
01179 int major = 1+m.random(department_array.department_count);
01180 yearInProgramPctArr =
01181 department_res[department_array[major]->department_id]->doctor_year_in_program_pct;
01182 }
01183 else if ( sl == DISTANCE_LEARN ) {
01184 yearInProgramPctArr = year_in_program_pct[UG_NONTRADITION];
01185 }
01186
01187
01188 int stuCountByYear[MAX_GRADUATE_YEARS+1];
01189 memset(stuCountByYear,0,sizeof(stuCountByYear));
01190
01191 int chkCount = 0;
01192 float pct = yearInProgramPctArr[0];
01193
01194 for (i=0; i<MAX_GRADUATE_YEARS+1 && pct<=1; i++) {
01195 stuCountByYear[i] = int(stuCountThisLevel * yearInProgramPctArr[i]);
01196
01197 chkCount += stuCountByYear[i];
01198 pct += yearInProgramPctArr[i+1];
01199 }
01200
01201
01202
01203 int diff = stuCountThisLevel - chkCount;
01204 err_when(diff < 0);
01205
01206 if ( diff > 0 ) {
01207 i = min(MAX_GRADUATE_YEARS, i);
01208 stuCountByYear[i] += diff;
01209 }
01210
01211
01212
01213
01214
01215
01216
01217
01218
01219
01220
01221
01222
01223
01224
01225
01226
01227 int year = MAX_GRADUATE_YEARS+1;
01228
01229 for (i=0; ; ) {
01230 if ( stuCountByYear[year-1] > 0 )
01231 stuCountByYear[year-1]--;
01232 else if ( year > 2 ) {
01233 year--;
01234 continue;
01235 }
01236 else
01237 break;
01238
01239 err_when(stuSortArray[i] < 1 || stuSortArray[i] > stuCountThisLevel);
01240
01241 stuStrPtr = (StudentStruct *) stuArr[sl].get(stuSortArray[i]);
01242 stuPtr = department_array[stuStrPtr->dept_recno]->student_array[stuStrPtr->stu_recno];
01243
01244 stuPtr->year_in_program = year;
01245
01246 i++;
01247 }
01248
01249 int finalStuCountThisLevel = i;
01250
01251
01252 if ( finalStuCountThisLevel != stuCountThisLevel ) {
01253 for (int j=finalStuCountThisLevel; j<stuCountThisLevel; j++) {
01254 stuStrPtr = (StudentStruct *) stuArr[sl].get(stuSortArray[j]);
01255 department_array[stuStrPtr->dept_recno]->student_array.del(stuStrPtr->stu_recno);
01256 stuStrPtr->dept_recno = 0;
01257 stuStrPtr->stu_recno = 0;
01258 }
01259 }
01260
01261
01262
01263
01264
01265 float failRate = 0;
01266
01267 for (int j=0; j<finalStuCountThisLevel; j++) {
01268 stuStrPtr = (StudentStruct *) stuArr[sl].get(stuSortArray[j]);
01269
01270
01271
01272
01273 if(stuStrPtr==NULL)
01274 continue;
01275 stuPtr = department_array[stuStrPtr->dept_recno]->student_array[stuStrPtr->stu_recno];
01276
01277 float newValue= 40+(stuPtr->talent_academic)*(.2f + .8f * ((50)-50)/100);
01278 newValue = math.single_response_func(0.0f, 0.1f, -70.11f, 53.65f, newValue);
01279
01280 failRate += newValue;
01281 }
01282
01283 #if(GAME_VERSION>=200)
01284
01285 failRate = math.safe_divide( failRate, (float)finalStuCountThisLevel );
01286 #else
01287 failRate /= finalStuCountThisLevel;
01288 #endif
01289
01290
01291
01292 PeerSchool* player = school_res.player_peer_school;
01293 const float expectedYearsToDegree[MAX_STUDENT_LEVEL] = { 4.47f, 7.65f, 1.05f, player->doc_time_to_degree-2, 7.65f };
01294 const char normYearsToDegree[MAX_STUDENT_LEVEL] = { 4,8,1,2,8 };
01295
01296
01297 float lagRate = expectedYearsToDegree[sl] / normYearsToDegree[sl];
01298
01299
01300
01301
01302
01303 this->delay_rate[sl] = 1 - (1-lagRate) / (1-failRate);
01304
01305
01306 }
01307
01308 mem_del( stuSortArray );
01309 }
01310
01311