luduscore
A rule-based, explainable console game recommendation engine — no AI/ML, no web framework, no database required. Give it a player's preferences, get back a ranked list of games with a numeric score and human-readable reasons for each recommendation.
Not affiliated with, endorsed by, or sponsored by Sony Interactive Entertainment. "PlayStation" and "PS5" are trademarks of Sony Interactive Entertainment Inc. This project is an independent, open-source tool compatible with console game preferences; it does not use any Sony trademark in its name.
Why rule-based, not ML?
Every score is fully traceable: each matching dimension (difficulty, genre,
playstyle, multiplayer, story-vs-gameplay balance) contributes a fixed,
named weight. There's no model, no training data, no black box — the
reasons returned with each result are literally built from the rules that
fired. See src/luduscore/engine.py for the
full scoring logic.
Install
pip install luduscore
Quickstart
from luduscore import ScoringEngine, UserProfile
engine = ScoringEngine() # uses the bundled 100-game starter catalog
profile = UserProfile(
skill_level="beginner",
genres=["adventure", "rpg"],
playstyle=["story-driven"],
difficulty="easy",
multiplayer=False,
story_weight=0.9, # 0.0 = pure gameplay, 1.0 = pure narrative
)
for result in engine.recommend(profile, top_n=5):
print(f"{result.score:5.2f} {result.title}")
for reason in result.reasons:
print(f" - {reason}")
The bundled catalog is a starter set, not a database
luduscore ships with 100 manually curated, real games as a default
catalog — enough to demo the engine and get useful results out of the box.
It is not meant to be a comprehensive game database. For anything
beyond demo/starter use, bring your own catalog:
# Fully replace the bundled catalog
engine = ScoringEngine(games_path="my_games.json")
engine = ScoringEngine(games=my_list_of_game_dicts)
# Or extend the bundled catalog instead of replacing it
engine = ScoringEngine(extra_games=[{...}, {...}])
engine.add_game({...})
engine.add_games([{...}, {...}])
engine.remove_game("elden-ring")
luduscore doesn't care where your data comes from — JSON file, MongoDB,
SQL, an API call — as long as it's converted to a list[dict] matching the
required schema before you hand it to ScoringEngine. Fetching/storage is
your app's job; scoring is this package's job.
Required game schema
Every game dict needs these keys (importable as luduscore.REQUIRED_GAME_KEYS):
| Key | Type | Notes |
|---|---|---|
id |
str |
Unique identifier (slug) |
title |
str |
Display name |
genres |
list[str] |
e.g. ["action-rpg", "open-world"] |
difficulty |
str |
One of: easy, easy-medium, medium, medium-hard, hard, very-hard |
playstyle |
list[str] |
e.g. ["combat-heavy", "story-driven"] |
multiplayer |
bool |
Has a meaningful multiplayer mode |
story_vs_gameplay |
float |
0.0 (pure gameplay) to 1.0 (pure narrative) |
tags (list[str]) is optional — it's descriptive metadata, not read by
the scoring logic.
add_game/add_games validate this schema and raise ValueError (naming
the exact missing keys) rather than silently scoring a malformed entry as
0 on that dimension.
API
ScoringEngine(games=None, games_path=None, extra_games=None)engine.recommend(profile: UserProfile, top_n: int | None = 10) -> list[ScoredResult]engine.score_game(game: dict, profile: UserProfile) -> ScoredResultengine.add_game(game: dict)/engine.add_games(games: list[dict])engine.remove_game(game_id: str) -> boolUserProfile(skill_level, genres=[], playstyle=[], difficulty=None, multiplayer=None, story_weight=0.5)ScoredResult(game_id, title, score, reasons)
Development
pip install -e ".[dev]"
pytest
License
MIT — see LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file luduscore-0.1.0.tar.gz.
File metadata
- Download URL: luduscore-0.1.0.tar.gz
- Upload date:
- Size: 20.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5cec3de4c2148cce7651a7b5f728b1087b43b5cc6c5120d3ff23c227ef68c8f6
|
|
| MD5 |
02a712e546d989b07f08a5e7185a8e3b
|
|
| BLAKE2b-256 |
2b3dcfc0a1590ecb4d7639cf09e47578118ecc7f995a23affa3f23c7f279d433
|
File details
Details for the file luduscore-0.1.0-py3-none-any.whl.
File metadata
- Download URL: luduscore-0.1.0-py3-none-any.whl
- Upload date:
- Size: 16.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
eef3216cceb76b0cec9a6a71869daf48d95263e516a81f41f47e6f77242562c5
|
|
| MD5 |
9ed3f2ae347caf60a9388a096a6e027d
|
|
| BLAKE2b-256 |
1b61c89de205ad81ceedcb0a7e81fde63ef883f87888cbb7c1501c18636dbaee
|