I generalised the simulation method of factoring in both current skill level and skill rate. I'm pretty sure this method is fine, but the code itself may need cleaning up. It may not even compile the first time and I might have missed some bugs.
const int max_xp = 29000;
const int xp_levels [] = {0, 500, 1100, 1800, 2600, 3500, 4500, 5600, 6800, 8100, 9500,
11000, 12600, 14300, 16100, 18000, 20000, 22100, 24300, 26600, 29000};
// xp(lvl) = 500*lvl + 100 * (lvl * (lvl -1)) / 2
// const int lev_size = sizeof(xp_levels) / sizeof(int); // 21 , unused
int get_level_from_xp(int xp) // Uses busection method. Assumes xp >= 0.
{ if (xp >= max_xp)
return 20;
int min = 0;
int max = 19;
int current = 10;
while (1)
{ if (xp < xp_levels[current])
{ max = current;
current = (min + max)/2;
} else if (xp > xp_levels[current+1])
{ min = current;
current = (min + max)/2;
} else
return current;
}
}
/* Simulation method for judging a dwarf's skill level and rate.
Inputs: dwarf's current xp and learning rate for a skill.
Output: rating based on simulating gaining experience in that skill.
*/
double simulate_skill_gain(int xp, int rate)
{ if (xp >= max_xp)
return 20;
if (rate == 0)
return get_level_from_xp(xp); // Obviously stays the same.
int sim_xp = max_xp; // 29k seems like a good value to me.
sim_xp = (sim_xp / 100.0) * rate; // This is how much XP will go towards skill learning.
int total_xp = sim_xp;
double ret = 0.0;
int curr_level = get_level_from_xp(xp);
int curr_xp = xp;
/* // Version of the while loop interpolating the level. It may be smoother.
while ((sim_xp > 0) && (curr_level < 20))
{ int xp_gap = xp_levels[curr_level+1] - curr_xp; // How much XP till mext level?
if (xp_gap > sim_xp)
xp_gap = sim_xp;
double low = (0.0 +curr_xp -xp_levels[curr_level]) / (xp_levels[curr_level+1] -xp_levels[curr_level]);
double high = (0.0 +curr_xp + xp_gap -xp_levels[curr_level]) / (xp_levels[curr_level+1] -xp_levels[curr_level]);
double avg_level = curr_level + (low + high) / 2.0; // Average scaled level for this iteration.
ret += xp_gap * avg_lvl;
curr_level++;
curr_xp = xp_levels[curr_level];
sim_xp -= xp_gap;
}
*/
// Alternate, simple version of the while loop, without the interpolation.
while ((sim_xp > 0) && (curr_level < 20))
{ int xp_gap = xp_levels[curr_level+1] - curr_xp; // How much XP till mext level?
if (xp_gap > sim_xp)
xp_gap = sim_xp;
ret += xp_gap * curr_level;
curr_level++;
curr_xp = xp_levels[curr_level];
sim_xp -= xp_gap;
}
if (sim_xp > 0)
ret += 20 * sim_xp;
ret /= total_xp;
return ret;
}