Skip to content

Fitness function

IndividualPlayer.calculate_fitness() in src/ga/player.py combines match results, movement, hits, and streaks. The terms are summed and then multiplied by a score-ratio multiplier and an optional shutout bonus.

Let P be the player's score, C the CPU score, and squash(x, k) = k × tanh(x / k).

Term Calculation Purpose
Score gap (P - C) × 17 Rewards winning by a larger margin and penalizes losses.
Movement bonus squash(left_moves + right_moves, 1000) × 2^(2 × move_ratio) Rewards useful movement, with a multiplier for moving in both directions. move_ratio is the smaller direction count divided by the larger, or zero if either direction has no moves.
Hits player_hits × (player_hits / (cpu_hits + 1)) × 2 Rewards player paddle hits relative to CPU hits.
Hit streak longest_player_hit_streak × 2.5 Rewards consecutive successful player hits.
Winning streak squash(longest_player_win_streak, 5) Rewards consecutive points while limiting this term's growth.

The sum is multiplied by (P / (C + 1) + 1)^2. A further 1.25 multiplier applies when the player scores more than one point and the CPU scores none. This means match score dominance has a strong effect on the final fitness, while the other terms provide secondary incentives.