AlgoRadar — an explainable recommender for CP practice
Hello Codeforces!
I built AlgoRadar, an open-source recommendation/analytics system for competitive programming practice.
Repository: Link
The goal is simple:
Given my public submission history, what should I practice next?
The system uses Codeforces as the strongest source because it provides public submissions, verdicts, problem ratings, tags, rating history, and problemset metadata. It also has adapters for LeetCode and CodeChef, but Codeforces is the main difficulty anchor.
1. Main idea
AlgoRadar converts public CP activity into explainable features and ranks unsolved problems by learning value, not just rating or popularity.
Rough pipeline:
handle
-> fetch public submissions/problem metadata
-> build profile/tag/difficulty features
-> classify focus areas
-> estimate solve probability
-> rank candidate problems
-> bucket into confidence/growth/stretch/avoid-for-now
-> diversify final recommendations
I intentionally used a baseline-first approach instead of a black-box model.
Why? Public solved history is useful but noisy. An accepted submission does not always prove independent ability, and a failed submission does not fully prove inability. So instead of pretending to have perfect labels, the system uses feature engineering, scorecards, caps, and behavioral tests.
2. Feature engineering
For every user/tag/problem, the system computes features like:
rating_gap = problem_rating - user_rating
tag_accuracy
attempts_on_tag
tag_solved_count
tag_avg_rating_solved
tag_max_rating_solved
recent_failures
recent_accuracy
popularity_log
rating_confidence
Examples:
tag_accuracy = accepted_submissions_on_tag / attempts_on_tag
tag_avg_rating_solved = average rating of accepted problems in that tag
tag_max_rating_solved = hardest accepted problem in that tag
The system does not trust accuracy alone.
For example:
2/2 solves != 40/60 solves
Both may look good, but the second gives much stronger evidence.
Also, solving many easy dp problems should not imply that a 2200-rated dp problem is easy. That is why average solved rating and hardest solved rating are used.
3. Focus / weakness classification
Tags are classified into:
Strong
Stable
Weak
Untouched
Over-attempted
The important distinction is:
Weak != Untouched
If a user has never practiced geometry, the system should not say "you are weak in geometry". It should say there is not enough evidence.
The classifier is rule-based and uses attempts, accuracy, recent failures, and solved depth. This is easier to inspect and debug than a fake supervised model trained on weak labels.
4. Solve probability scorecard
The solve estimate is mainly driven by rating gap:
rating_gap = problem_rating - user_rating
Then tag evidence adjusts it.
Conceptually:
logit =
base
- rating_gap_penalty
+ tag_volume_bonus
+ hardest_solved_bonus
+ average_solved_rating_bonus
+ overall_experience_bonus
+ popularity_bonus
- recent_failure_penalty
- uncertainty_penalty
Then the logit is converted into probability:
p = 1 / (1 + exp(-logit))
But the raw probability is capped.
Reason: a problem near the user's rating should not become 95% just because the user solved many problems before. Same-level problems are usually growth attempts, not guaranteed solves.
The final probability is bucketed as:
> 75% -> confidence
45-75% -> growth
25-45% -> stretch
< 25% -> avoid-for-now
This makes the output actionable instead of giving only one sorted list.
5. Recommendation ranking
The recommender first removes already solved problems:
candidates = all_problems - solved_problem_ids
Then candidates are scored using:
solve probability
growth fit
weak/focus tag overlap
tag evidence
topic familiarity
rating fit
log popularity
diversity penalties
The main idea:
The best recommendation is not necessarily the easiest problem or the most similar problem. It should be useful for improvement.
6. Topic familiarity with cosine similarity
I added a solved-tag vector signal.
For a user, build a tag-count vector:
dp: 10
graphs: 6
math: 4
Then L2-normalize it:
u[j] = count[j] / sqrt(sum(count[k]^2 over all tags k))
For each candidate problem, build a binary tag vector t.
Then:
sim(problem, user) = dot(t, u) / norm(t)
This measures how familiar the candidate's topics are to the user.
But this is only a small signal. If it dominates, the system will keep recommending comfort-zone problems forever. So AlgoRadar uses it as topic familiarity, not as the whole recommender.
7. Gaussian rating fit
I also added a smooth rating-fit score:
rating_fit = exp(-((problem_rating - user_rating)^2) / (2 * sigma^2))
where:
sigma = 0.3 * user_rating
This gives a smooth peak near the user's current level instead of a hard cutoff.
For a 1200-rated user:
1200 problem -> high fit
1400 problem -> reasonable fit
2000 problem -> low fit
600 problem -> also lower fit
This is used as a ranking feature, not as the entire difficulty model.
8. Final learning-value score
A simplified version of the ranking score is:
learning_value =
1.15 * growth_fit
+ 0.52 * tag_similarity
+ 0.32 * ceiling_score
+ 0.22 * evidence_score
+ 0.18 * quality_score
+ 0.12 * tag_cosine_similarity
+ 0.14 * rating_fit
- 0.00028 * rating_distance
Then:
rank_score = learning_value + 0.16 * solve_probability
where:
growth_fit = 1 - abs(solve_probability - 0.6) / 0.6
So the system prefers problems around a realistic growth zone, not extremely easy problems and not nearly impossible problems.
The weights are heuristic and open to tuning.
9. Similar-problem search
There is also optional similar-problem search.
Default fallback: TF-IDF over problem name, rating, and tags.
If available: MiniLM embeddings for semantic similarity.
This is used to find related or slightly harder problems around a recommendation. It is optional because the recommender should not depend on transformer downloads or heavy runtime dependencies.
10. Testing
The tests focus on behavior, not only imports.
Examples:
harder problem should generally not get higher solve probability
same-rating problem should not get unrealistic 90%+ probability
strong tag depth should improve estimate
cold tag should reduce confidence
solved problems should not be recommended again
calibration should affect cross-platform estimates
This matters because a recommender can run without crashing and still give misleading advice.
11. Limitations
Important limitations:
public solved history is noisy
tags are broad
weights are heuristic
CodeChef/LeetCode mappings are approximate
no real feedback loop yet
recommendation quality needs real user outcome data
Future improvements:
viewed / attempted / solved / skipped feedback
time-to-solve tracking
calibration curves and Brier score
better mashup generation
better tag hierarchy
learned model after enough real outcome labels
12. Conclusion
AlgoRadar is my attempt at an explainable CP recommendation system.
It combines:
rating gap
tag depth
weakness classification
solve probability
topic familiarity
Gaussian rating fit
log popularity
bucketed practice modes
diversity
It is not meant to be an oracle. It is meant to be a practical tool for deciding what to practice next.
I would appreciate suggestions, especially on:
better scoring functions
better rating-fit curves
tag similarity improvements
evaluation metrics
mashup/workout generation
Repository: Link
Thanks for reading!








Nice:)
Nice tool for practise NonTourist.
I've converted it into a website for those who would like it in a more accessible interface:
https://algoradar-6y34.onrender.com/
how do i add this to my browser??
Great Work !. But how did you evaluate the recommendations system? And how did you evaluate the focus / weakness classification model as well, how good is it?
it all has been mentioned in the above blog . the whole algo had been briefed there , if you still have any concerns , you can just message me
Are you retarded nigga?
Remove Non from your handle and see magic