adaptive_gamification 0.0.1
adaptive_gamification: ^0.0.1 copied to clipboard
Adaptive gamification engine powered by reinforcement learning for dynamic difficulty adjustment.
Adaptive Gamification (Flutter) #
A Flutter package that provides an adaptive gamification / dynamic difficulty adjustment (DDA) engine powered by a Reinforcement Learning (RL) policy trained externally (e.g., PPO in Python) and exported as a JSON policy table.
What you get: a small, reusable on-device inference layer that loads the trained policy and produces deterministic difficulty decisions inside a Flutter app.
Why this is still Reinforcement Learning #
This package runs a policy that was learned via RL optimization:
- The policy is trained by an RL algorithm (e.g., PPO) to optimize a reward objective.
- At runtime, the engine follows the RL decision pipeline: state → decision.
- The app supplies an observed learner state; the engine returns a difficulty decision consistent with the learned policy.
Important: the package deliberately does not train the agent inside Flutter. Training belongs to your research/training pipeline.
What this library is (and is not) #
✅ This library is:
- A reusable Flutter package with a small, clean public API.
- A lightweight policy execution layer (policy lookup + deterministic fallback).
- Suitable for offline/on-device usage (no server required).
- Compatible with PPO (and other RL methods) as long as you export the required JSON format.
❌ This library is not:
- An RL training implementation.
- An online-learning system that retrains inside the app.
- A mandatory backend service.
Backend is optional: you can deliver a policy from a server and initialize the engine with
initFromString(...), but the package works fully offline.
Features #
- RL-driven dynamic difficulty adjustment using an exported policy table
- Deterministic inference (exact lookup + deterministic fallback)
- State mapping (maps app-level signals → RL state features)
- Pluggable policy (load any compatible policy JSON)
- Clean API surface:
AdaptiveEngine.initFromAsset(...)AdaptiveEngine.initFromString(...)AdaptiveEngine.decide(...)
Policy JSON format (required) #
The engine expects a JSON List of entries. Each entry must include:
state:{ eng, mot, flow, perf }with values in [0.0, 1.0]decision: at minimumnext_difficulty: one ofveryEasy | easy | medium | hard | veryHardreason: a string
Example (single entry):
{
"state": {"eng": 0.25, "mot": 0.50, "flow": 0.75, "perf": 1.00},
"action": 3,
"decision": {
"next_difficulty": "hard",
"reason": "High performance and flow"
}
}
Discretization / grid #
Most exported policies are defined on a discrete grid (commonly 0.25). The included StateMapper discretizes the incoming state to match the training grid before lookup.
If your policy was exported with a different grid resolution, update the
gridconstant inStateMapperto match.
Installation #
A) Local path (recommended during development) #
In your app’s pubspec.yaml:
dependencies:
adaptive_gamification:
path: ../adaptive_gamification
B) Git dependency #
dependencies:
adaptive_gamification:
git:
url: https://github.com/AmerNakhal/adaptive-gamification-library.git
path: adaptive_gamification
C) pub.dev #
Once published:
dependencies:
adaptive_gamification: ^0.0.1
Add your policy JSON to the app #
This package does not bundle a policy by default. Policies are research artifacts and depend on your training/export.
Add your policy file to your Flutter app’s assets.
Example app pubspec.yaml:
flutter:
assets:
- assets/data/adaptive_policy.json
Quick start #
import 'package:adaptive_gamification/adaptive_gamification.dart';
final engine = AdaptiveEngine();
Future<void> main() async {
// Load policy from the *app* asset bundle
await engine.initFromAsset(
policyAssetPath: 'assets/data/adaptive_policy.json',
);
final state = UserState(
currentDifficultyIndex: 2, // your app mapping (e.g., 0..4)
accuracy: 0.70, // 0.0..1.0
responseTime: 1.20, // seconds
correctStreak: 3,
);
final decision = engine.decide(state);
// nextDifficulty is one of: veryEasy, easy, medium, hard, veryHard
print('Next difficulty: ${decision.nextDifficulty}');
print('Reason: ${decision.reason}');
}
Public API #
AdaptiveEngine #
Future<void> initFromAsset({ required String policyAssetPath, AssetBundle? bundle })- Loads policy JSON from the Flutter asset bundle.
void initFromString(String jsonString)- Loads policy JSON from a raw string (useful for backend delivery or tests).
AdaptiveDecision decide(UserState state)- Returns the recommended next difficulty and a reason.
UserState #
Minimal learner signals expected by the engine:
currentDifficultyIndex(int)accuracy(double, 0..1)responseTime(double, seconds)correctStreak(int)
AdaptiveDecision #
nextDifficulty(String)reason(String)
How it works (internals) #
- PolicyLoader reads the JSON list and indexes it by a consistent key:
- key format:
"0.25,0.50,0.75,1.00"(fixed 2 decimals, comma-separated)
- key format:
- StateMapper converts
UserState→ RL state[eng, mot, flow, perf]:perf = accuracyeng = mean(accuracy, 1/(responseTime+1))mot = correctStreak / 5flow = 1 - 2*abs(perf - 0.5)- then discretize to the training grid (default: 0.25)
- DecisionEngine performs a fast lookup in the indexed policy.
- If no exact key exists, a deterministic fallback decision is returned.
Example #
A runnable example app is included under example/.
cd example
flutter pub get
flutter run
Library structure #
adaptive_gamification/
├── lib/
│ ├── adaptive_gamification.dart
│ └── src/
│ ├── core/
│ │ ├── decision_engine.dart
│ │ └── policy_loader.dart
│ ├── engine/
│ │ └── adaptive_engine.dart
│ ├── models/
│ │ ├── user_state.dart
│ │ └── adaptive_decision.dart
│ └── utils/
│ └── state_mapper.dart
├── example/
├── README.md
└── pubspec.yaml
Testing #
flutter test
License #
See LICENSE.