DriverPersonality is a simple immutable data type describing AI driver traits. It holds driving parameters (lateral acceleration, top speed factor, steering, aggression, mistake rate, lateral bias, look-ahead and drift chance) and has a Create(seed,difficulty) factory that seeds the RNG and returns randomized values per difficulty.
namespace Machines.Player;
/// <summary>
/// Driver traits and personality for driving style.
/// </summary>
public sealed class DriverPersonality
{
/// <summary>
/// Lateral acceleration factor (0-1)
/// </summary>
public float LatAccel { get; init; }
/// <summary>
/// Top speed factor (0–1)
/// </summary>
public float MaxSpeed { get; init; }
/// <summary>
/// Steering sharpness factor (0–1)
/// </summary>
public float SteerSharpness { get; init; }
/// <summary>
/// Steering smoothing factor (0–1)
/// </summary>
public float SteerSmoothing { get; init; }
/// <summary>
/// How aggressive the bot is in overtaking and defending (0–1)
/// </summary>
public float Aggression { get; init; }
/// <summary>
/// How often the bot makes mistakes (0–1)
/// </summary>
public float MistakeRate { get; init; }
/// <summary>
/// Track-side preference: 0 = center, -1 = left, 1 = right
/// </summary>
public float LateralBias { get; init; }
/// <summary>
/// Look-ahead scale: 1 = normal, more = further, less = shorter
/// </summary>
public float LookAheadScale { get; init; }
/// <summary>
/// Chance (0–1) that the bot will drift on any given corner opportunity.
/// </summary>
public float DriftChance { get; init; }
/// <summary>
/// Creates a randomized personality for the given seed and difficulty
/// </summary>
public static DriverPersonality Create( int seed, BotDifficulty difficulty )
{
Game.SetRandomSeed( seed );
float Rand() => Game.Random.NextSingle();
float Between( float baseValue, float spread ) => baseValue + (Rand() - 0.5f) * 2f * spread;
return difficulty switch
{
BotDifficulty.Easy => new DriverPersonality
{
LatAccel = Between( 0.25f, 0.033f ).Clamp( 0f, 1f ),
MaxSpeed = Between( 0.375f, 0.0375f ).Clamp( 0f, 1f ),
SteerSharpness = Between( 0.2f, 0.085f ).Clamp( 0f, 1f ),
SteerSmoothing = Between( 0.333f, 0.125f ).Clamp( 0f, 1f ),
Aggression = Between( 0.25f, 0.15f ).Clamp( 0f, 1f ),
MistakeRate = Between( 0.15f, 0.08f ).Clamp( 0f, 1f ),
LateralBias = Between( 0f, 0.6f ).Clamp( -1f, 1f ),
LookAheadScale = Between( 1.0f, 0.15f ),
DriftChance = Between( 0.2f, 0.1f ).Clamp( 0f, 1f ),
},
BotDifficulty.Hard => new DriverPersonality
{
LatAccel = Between( 1.0f, 0f ).Clamp( 0f, 1f ),
MaxSpeed = Between( 1.0f, 0.03f ).Clamp( 0f, 1f ),
SteerSharpness = Between( 1.0f, 0.05f ).Clamp( 0f, 1f ),
SteerSmoothing = Between( 1.0f, 0.05f ).Clamp( 0f, 1f ),
Aggression = Between( 0.8f, 0.15f ).Clamp( 0f, 1f ),
MistakeRate = Between( 0.015f, 0.015f ).Clamp( 0f, 1f ),
LateralBias = Between( 0f, 0.6f ).Clamp( -1f, 1f ),
LookAheadScale = Between( 1.2f, 0.15f ),
DriftChance = Between( 0.7f, 0.15f ).Clamp( 0f, 1f ),
},
_ => new DriverPersonality
{
LatAccel = Between( 0.458f, 0.05f ).Clamp( 0f, 1f ),
MaxSpeed = Between( 0.5625f, 0.0375f ).Clamp( 0f, 1f ),
SteerSharpness = Between( 0.43f, 0.114f ).Clamp( 0f, 1f ),
SteerSmoothing = Between( 0.5f, 0.167f ).Clamp( 0f, 1f ),
Aggression = Between( 0.5f, 0.2f ).Clamp( 0f, 1f ),
MistakeRate = Between( 0.06f, 0.04f ).Clamp( 0f, 1f ),
LateralBias = Between( 0f, 0.6f ).Clamp( -1f, 1f ),
LookAheadScale = Between( 1.1f, 0.15f ),
DriftChance = Between( 0.45f, 0.2f ).Clamp( 0f, 1f ),
},
};
}
}