A Scrabble word-study and spaced-repetition training system built with .NET 10.
Trie-powered anagram search, cardbox scheduling backed by SQLite, 12 analytics queries, and an interactive quiz workflow — all served from a single Blazor + ASP.NET Core host.
- Anagram / sub-anagram search — trie-based engine loaded lazily from a flat word list
- Pattern matching — wildcard search across the lexicon
- Word distance & alphagram distance — letter-difference calculations
- Cardbox spaced repetition — SQLite-backed scheduling with streak, difficulty, and history tracking
- 12 analytics queries — due now, priority items, error rate, regressions, blind spots, forgetting curve, and more
- Interactive web quiz — progressive answer entry, per-answer feedback, keyboard-first UX
- Reinforcement list — tracks fully-correct answers for review and one-click export to text file
- Paged result tables — configurable page size, first/prev/next/last navigation
- Quiz on any result set — run a quiz directly from any word-based analytics query
- REST API — minimal API endpoints for anagram search, cardbox stats, and health checks
- CLI mode — the original power-user console interface still works unchanged
BonusAccumulator.sln
│
├── WordServices/ Core domain logic (pure C#, no web deps)
│ ├── TrieLoading/ Lazy trie construction from dictionary file
│ ├── TrieSearching/ Thread-safe anagram/build/pattern search
│ ├── Analytics/ 13 query interfaces + result types
│ ├── Output/ Word formatting
│ └── WordService.cs Facade: search, quiz, session, distance
│
├── CardboxDataLayer/ Data access (EF Core + SQLite)
│ ├── Entities/ Question, QuestionHistory, stats models
│ ├── Repositories/ IQuestionRepository
│ ├── Analytics/ SQL-based analytics query implementations
│ └── Services/ AnalyticsService aggregate
│
├── WordServices.Host/ Single-host web app (Blazor Server + API)
│ ├── Components/Pages/ Razor components (Analytics, Quiz, Stats, Pager)
│ ├── Analytics/ Quiz session service, query runner, paging container
│ ├── Endpoints/ Minimal API (anagram, quiz, cardbox, health)
│ ├── Configuration/ DI wiring, settings provider
│ └── Middleware/ Global exception handling
│
├── BonusAccumulator/ Original CLI host
│
├── WordServicesTests/ NUnit tests for WordServices
├── CardboxDataLayerTests/ NUnit tests for CardboxDataLayer
└── WordServices.Host.Tests/ NUnit tests for host logic (quiz state, paging, analytics)
| Layer | Technology |
|---|---|
| Runtime | .NET 10 / C# 14 |
| Web UI | Blazor Server (Interactive Server render mode) |
| API | ASP.NET Core Minimal APIs |
| Data | EF Core + SQLite |
| Search engine | Custom trie (lazy-loaded, thread-safe) |
| Testing | NUnit 4 + FluentAssertions |
| Styling | Vanilla CSS (dark theme, no framework dependency) |
- .NET 10 SDK
- A word list file (one word per line, e.g. a Scrabble dictionary export)
- An SQLite database with the cardbox schema (created by the data layer on first use, or use an existing Zyzzyva-format database)
git clone https://github.com/YOUR_USER/BonusAccumulator.git
cd BonusAccumulatorEdit WordServices.Host/appsettings.json:
{
"DictionaryPath": "C:\\Lexicon\\list.txt",
"SessionOutputPath": "C:\\WordOutput\\session{0}.txt",
"ConnectionStrings": {
"CardboxDatabase": "Data Source=C:\\path\\to\\Anagrams.db"
}
}| Setting | Purpose |
|---|---|
DictionaryPath |
Absolute path to your word list (one word per line) |
SessionOutputPath |
Format string for session export files ({0} = timestamp) |
ConnectionStrings:CardboxDatabase |
SQLite connection string for spaced-repetition data |
You can also override via environment variables:
$env:DictionaryPath = "C:\Lexicon\list.txt"
$env:ConnectionStrings__CardboxDatabase = "Data Source=C:\path\to\Anagrams.db"cd WordServices.Host
dotnet runcd BonusAccumulator
dotnet run| Method | Route | Description |
|---|---|---|
GET |
/api/health |
Health check |
GET |
/api/health/detail |
Health detail with timestamp |
POST |
/api/anagrams/search |
Anagram / build / pattern search |
POST |
/api/quiz/start |
Start a quiz session |
POST |
/api/quiz/answer |
Submit a quiz answer |
GET |
/api/cardbox/stats |
Cardbox statistics |
curl -X POST https://localhost:7200/api/anagrams/search \
-H "Content-Type: application/json" \
-d '{"rack":"SATIRE","mode":"Anagram"}'dotnet build BonusAccumulator.sln
dotnet test BonusAccumulator.slnRun a single test project:
dotnet test WordServices.Host.Tests/WordServices.Host.Tests.csprojdotnet publish WordServices.Host/WordServices.Host.csproj -c Release -o ./publish/hostThe published output is a self-contained web app. Copy it to your server, set the configuration
environment variables, and run WordServices.Host.exe.
- AI guidance —
AI_GUIDANCE.mdat the repo root defines coding standards enforced across the solution (novar, no comments, explicit types, one file per type, NUnit conventions). - Trie is lazy-loaded — the dictionary file is read once on first search request. Subsequent requests reuse the in-memory trie. The trie and searcher are registered as singletons and are thread-safe.
- Quiz is session-scoped —
QuizSessionServiceis registered as scoped (one per SignalR circuit). Quiz state lives in memory for the duration of the Blazor session. - Analytics queries — each of the 12 analytics queries is a separate interface (
IGetDueNow,IGetHighestErrorRate, etc.) implemented inCardboxDataLayer.Analyticswith raw SQL for performance. The host dispatches viaAnalyticsQueryRunner.
- Persistent quiz history (track scores across sessions)
- bUnit component tests for Razor pages
- User authentication and multi-user support
- Mobile-friendly responsive layout improvements
- Batch import/export of word lists
- Configurable quiz modes (timed, weighted by error rate)
- Docker containerization
- CI/CD pipeline with GitHub Actions
Licensed under the MIT License. See LICENSE for details.