A Laravel-based educational cricket game that combines live cricket match data with math practice questions. Students answer math questions based on real-time cricket match statistics, making learning fun and engaging.
- Overview
- API Layer Architecture
- Practice Mode
- Project Structure
- Database Schema
- Setup Instructions
- Configuration
- Routes and Controllers
- Key Features
Crickmaths is an educational platform that gamifies math learning by integrating live cricket match data. The application fetches real-time cricket match information from external APIs, stores it in a database, and uses this data to generate math questions for students. Additionally, it includes a Practice Mode where students can practice math questions without needing a live match.
The application is built with Laravel (PHP framework) and uses a service-oriented architecture to handle API integrations, data transformation, and database operations.
The API layer is the core component that handles all cricket data fetching, processing, and storage. It's designed with reliability, scalability, and maintainability in mind.
The API layer is implemented using a Service Pattern with the CricketApiService class located at app/Services/CricketApiService.php. This service acts as a centralized interface for all cricket data operations, abstracting away the complexity of dealing with multiple API providers.
-
Abstraction: Controllers don't directly interact with external APIs. Instead, they use the
CricketApiServicewhich provides a clean, consistent interface. -
Separation of Concerns: The service handles API communication, data transformation, and error handling, while controllers focus on business logic and view rendering.
-
Single Responsibility: Each method in the service has a specific purpose - fetching live matches, getting scorecards, or mapping data formats.
The system supports multiple cricket data providers with an intelligent fallback mechanism to ensure high availability.
The primary API provider is Cricbuzz, accessed through RapidAPI. This provider offers:
- Base URL:
https://cricbuzz-cricket2.p.rapidapi.com - Endpoints:
- Live Matches:
/matches/v1/live - Scorecard:
/mcenter/v1/{matchId}/scard
- Live Matches:
- Authentication: Uses RapidAPI headers (
X-RapidAPI-HostandX-RapidAPI-Key) - Timeout: 30 seconds per request
The backup provider is CricketData API (cricapi.com), which serves as a fallback when the primary API fails:
- Base URL:
https://api.cricapi.com/v1 - Endpoints:
- Live Matches:
/currentMatches - Scorecard:
/match_info
- Live Matches:
- Authentication: Uses API key as a query parameter
- Timeout: 30 seconds per request
The fallback mechanism works as follows:
-
Priority Order: The system tries providers in the order specified in
config/cricket.php(default:['cricbuzz', 'backup']). -
Error Handling: If a provider fails (network error, timeout, invalid response), the system:
- Logs a warning with the error message
- Automatically tries the next provider in the priority list
- Continues until a provider succeeds or all providers are exhausted
-
Graceful Degradation: If all providers fail, the system returns an empty array and logs an error, allowing the application to continue functioning (though without match data).
-
No User Impact: The fallback happens transparently - users don't see errors, and the application continues to work with whatever data is available.
The CricketApiService provides three main public methods:
Fetches all currently live cricket matches from the API providers.
Process Flow:
- Iterates through providers in priority order
- For each provider, calls the provider-specific method (
getCricbuzzLiveMatches()orgetBackupLiveMatches()) - If successful, maps the response to a standardized format
- Returns the mapped data or tries the next provider
Return Format: Array of match objects with standardized structure:
[
'match_id' => string,
'type' => string (T20, ODI, etc.),
'match_type' => string (series name),
'is_live' => string (live, completed, upcoming),
'result' => string (status message),
'match_location' => string (venue),
'team_details' => array (team scores and information)
]Fetches featured matches for display on the homepage. This method:
- Uses the same fallback mechanism as
getLiveMatches() - Transforms the data into a format expected by the frontend
- Returns matches in a nested structure:
['data' => ['featurematch' => [...]]]
Use Case: Homepage display, match selection interface
Fetches detailed scorecard information for a specific match.
Process Flow:
- Takes a match ID as parameter
- Tries each provider in priority order
- For Cricbuzz: Replaces
{matchId}placeholder in the endpoint URL - For CricketData: Passes match ID as a query parameter
- Maps the response to a standardized scorecard format
- Returns detailed match data including:
- Batting statistics (runs, balls, strike rate, dismissal info)
- Bowling statistics (overs, runs, wickets, economy)
- Extras (byes, leg byes, wides, no balls)
- Fall of wickets (FOW)
- Team totals and run rates
Return Format: Nested structure with full scorecard:
[
'data' => [
'getScoreCard' => [
'fullScoreCard' => [
[
'battingTeamID' => int,
'battingTeamName' => string,
'runsScored' => int,
'wickets' => int,
'overs' => float,
'batting' => array,
'bowling' => array,
'extras' => array,
'fow' => array,
// ... more fields
]
]
]
]
]One of the most critical aspects of the API layer is data normalization. Different API providers return data in different formats, so the service includes comprehensive mapping functions to convert all responses into a standardized format.
Live Matches Mapping (mapCricbuzzLiveMatchesToFormat):
- Extracts matches from nested structure:
typeMatches → seriesMatches → matches - Filters out Test matches (only T20, ODI, etc.)
- Maps match status:
In Progress→live,Complete→completed,Stumps→live - Extracts team information and scores from
matchScoreobject - Handles multiple innings and selects the latest one for each team
- Combines venue information (ground + city)
Scorecard Mapping (mapCricbuzzScorecardToFormat):
- Processes each innings in the scorecard array
- Maps batting data: player names, runs, balls, fours, sixes, strike rate, dismissal info
- Maps bowling data: overs, runs, wickets, maidens, economy, dot balls
- Extracts extras: byes, leg byes, wides, no balls, penalties
- Processes fall of wickets with player information and over/ball details
- Handles captain and wicket-keeper flags
- Calculates run rates and projections
Live Matches Mapping (mapCricketDataLiveMatchesToFormat):
- Processes array of match objects
- Filters out Test matches
- Extracts team information from
teamInfoarray - Maps scores from
scorearray - Determines match status from
matchStartedandmatchEndedflags - Extracts series name from match name string
Scorecard Mapping (mapCricketDataScorecardToFormat):
- Creates minimal scorecard structure (CricketData provides less detail than Cricbuzz)
- Extracts basic score information (runs, wickets, overs)
- Calculates run rate from runs and overs
- Creates placeholder arrays for detailed statistics (not available in this API)
The API layer implements comprehensive error handling:
- Exception Catching: Each API call is wrapped in try-catch blocks
- Logging: All errors are logged using Laravel's Log facade:
- Warnings for individual provider failures
- Errors when all providers fail
- Includes error messages and context (match ID, provider name)
- Graceful Failure: Errors don't crash the application - they trigger fallback or return empty data
- HTTP Status Checking: Validates HTTP response status codes before processing
- Response Validation: Checks for required fields in API responses before mapping
After fetching data from APIs, the system stores it in the database for quick access and to reduce API calls.
One critical challenge is that API providers return match IDs as UUIDs (long strings), but the database match_id column is an integer. The system includes a conversion function:
convertMatchIdToInteger($matchId) in PublicController:
- If the ID is already numeric, ensures it fits in INT range using modulo
- If it's a UUID, uses
crc32()hash function to convert to integer - Applies modulo operation to ensure the value fits in signed INT range (-2,147,483,648 to 2,147,483,647)
- This ensures database compatibility without schema changes
-
Live Matches Table (
livestable):- Stores basic match information: type, match_type, match_id, is_live, result, match_location
- Stores team_details as JSON: array of teams with scores
- Uses
updateOrCreateto update existing matches or create new ones
-
Live Matches Detail Table (
livematchestable):- Stores detailed scorecard information for each innings
- One record per match per batting team
- Stores complex data as JSON: batting array, bowling array, extras, FOW, etc.
- Links to
livestable viamatch_id
-
Update Strategy:
- Uses
updateOrCreatewith composite keys (match_id + battingTeamID) - Updates existing records if match already exists
- Creates new records for new matches or innings
- Uses
The system includes an automated data fetching mechanism via the getDataAuto() method in PublicController.
- Cron Job Setup: The route
/croncallsgetDataAuto()method - Scheduled Execution: Server cron job calls this endpoint periodically (e.g., every 5 minutes)
- Fetch Process:
- Calls
CricketApiService->getFeaturedMatches()to get current matches - Filters out Test matches
- For each match:
- Converts match ID to integer
- Fetches detailed scorecard using
getScorecard() - Updates or creates records in
livestable - Updates or creates detailed scorecard in
livematchestable
- Calls
- Error Handling: Wrapped in try-catch to prevent cron job failures
- Keeps database up-to-date with latest match information
- Reduces API calls during user requests (data is pre-fetched)
- Improves response times (serving from database is faster than API calls)
- Handles API failures gracefully without affecting user experience
All API settings are centralized in config/cricket.php:
'cricbuzz' => [
'api_key' => env('CRICBUZZ_API_KEY'),
'base_url' => env('CRICBUZZ_BASE_URL', 'https://cricbuzz-cricket2.p.rapidapi.com'),
'host' => env('CRICBUZZ_HOST', 'cricbuzz-cricket2.p.rapidapi.com'),
'endpoints' => [
'live_matches' => '/matches/v1/live',
'scorecard' => '/mcenter/v1/{matchId}/scard',
],
],
'backup' => [
'api_key' => env('CRICKETDATA_API_KEY'),
'base_url' => env('CRICKETDATA_BASE_URL', 'https://api.cricapi.com/v1'),
'endpoints' => [
'live_matches' => '/currentMatches',
'scorecard' => '/match_info',
],
],
'priority' => ['cricbuzz', 'backup'],This configuration allows:
- Easy switching between providers
- Environment-specific API keys (development vs production)
- Simple addition of new providers
- Centralized endpoint management
- Caching: Database storage acts as a cache layer, reducing API calls
- Timeout Settings: 30-second timeout prevents hanging requests
- Efficient Queries: Uses
updateOrCreateto minimize database operations - JSON Storage: Complex nested data stored as JSON, reducing table complexity
- Lazy Loading: Data fetched only when needed (on-demand for scorecards)
- API Key Protection: API keys stored in
.envfile, never committed to repository - Input Validation: Match IDs validated before database queries
- SQL Injection Prevention: Uses Eloquent ORM (parameterized queries)
- Error Message Sanitization: Error logs don't expose sensitive information
- Rate Limiting: Consider implementing rate limiting for API endpoints
Practice Mode is a standalone feature that allows students to practice math questions without requiring a live cricket match.
No Database Dependency: All practice questions are stored in a PHP data class (app/Data/PracticeQuestions.php), not in the database. This makes the feature:
- Fast (no database queries)
- Simple (no migrations needed)
- Portable (easy to add/remove questions)
Questions are organized by grade level (3, 4, and 5), with 10 questions per grade. Each question includes:
- Question Text: The math problem (e.g., "What is 15 + 23?")
- Choices: Array of 4 multiple-choice options
- Correct Answer: Index of the correct choice (0-based)
-
Grade Selection (
/practice):- User selects their grade (3, 4, or 5)
- JavaScript enables the "Start Practice" button
- Button sends AJAX request to
/practice/start
-
Question Loading (
/practice/start):- Server validates grade (must be 3, 4, or 5)
- Retrieves questions for selected grade
- Shuffles questions randomly for variety
- Returns JSON with questions, grade, and total count
-
Game Play (
/practice/play):- Frontend loads questions from sessionStorage
- Displays one question at a time with progress bar
- User selects an answer
- JavaScript sends answer to
/practice/answervia AJAX - Server validates answer and returns correctness
- Frontend shows immediate feedback
- User navigates through questions with Next/Back buttons
-
Answer Validation (
/practice/answer):- Server receives question index, selected answer, grade, and all questions
- Validates question index exists
- Compares selected answer with correct answer
- Returns JSON with correctness, correct answer, and selected answer
-
Results Display (
/practice/results):- Results stored in browser's
sessionStorage(not server) - JavaScript calculates score, percentage, correct/incorrect counts
- Displays performance message based on score
- Provides options to practice again or return home
- Results stored in browser's
Practice Mode uses browser sessionStorage to:
- Store questions and answers during the session
- Track user progress
- Calculate final results
- Persist data across page navigation
Benefits:
- No server-side session management needed
- Works without user authentication
- Data cleared when browser tab closes
- Fast and efficient
Practice Mode is accessible to everyone without:
- User registration
- Login authentication
- Database records
- Server-side session storage
This makes it ideal for:
- Quick practice sessions
- Guest users
- Testing and demos
- Educational purposes
cricmaths.billionreaders.org/
├── app/
│ ├── Data/
│ │ └── PracticeQuestions.php # Practice mode questions
│ ├── Http/
│ │ ├── Controllers/
│ │ │ ├── PublicController.php # Main controller (API, matches, games)
│ │ │ └── PracticeController.php # Practice mode controller
│ │ └── Middleware/
│ ├── Models/ # Eloquent models
│ │ ├── Live.php # Live matches model
│ │ ├── Livematch.php # Detailed scorecard model
│ │ ├── User.php
│ │ ├── Score.php
│ │ └── ...
│ └── Services/
│ └── CricketApiService.php # API service layer
├── config/
│ ├── app.php # App configuration (baseURL)
│ └── cricket.php # Cricket API configuration
├── database/
│ └── migrations/ # Database migrations
├── resources/
│ └── views/
│ ├── practice/ # Practice mode views
│ │ ├── index.blade.php # Grade selection
│ │ ├── play.blade.php # Game interface
│ │ └── results.blade.php # Results display
│ ├── index.blade.php # Homepage
│ ├── after-start.blade.php # Match selection
│ └── ...
├── routes/
│ └── web.php # Application routes
└── README.md
Stores basic live match information:
id: Primary keymatch_id: Integer (converted from UUID)type: Match type (T20, ODI, etc.)match_type: Series nameis_live: Status (live, completed, upcoming)result: Status messagematch_location: Venue informationteam_details: JSON array of team scores
Stores detailed scorecard information:
id: Primary keymatch_id: Foreign key to lives tablebattingTeamID: ID of batting teambattingTeamName: Name of batting teamrunsScored: Total runswickets: Wickets fallenovers: Overs bowledrunRate: Current run ratebatting: JSON array of batsmen statisticsbowling: JSON array of bowler statisticsextras: JSON object of extrasfow: JSON array of fall of wicketstotal: JSON object of team totals
users: User accountsscores: User game scoresscoreboards: Leaderboard dataquestions: Math questions for live gamesanswers: User answers to questions
- PHP >= 7.4
- Composer
- MySQL/MariaDB
- Node.js and NPM (for assets)
- Web server (Apache/Nginx) or PHP built-in server
-
Clone the repository:
git clone <repository-url> cd cricmaths.billionreaders.org
-
Install PHP dependencies:
composer install
-
Install Node dependencies (if needed):
npm install
-
Environment Configuration:
cp .env.example .env php artisan key:generate
-
Configure
.envfile:APP_URL=http://localhost DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=cricmaths DB_USERNAME=your_username DB_PASSWORD=your_password # Cricket API Keys CRICBUZZ_API_KEY=your_cricbuzz_api_key CRICBUZZ_BASE_URL=https://cricbuzz-cricket2.p.rapidapi.com CRICBUZZ_HOST=cricbuzz-cricket2.p.rapidapi.com CRICKETDATA_API_KEY=your_backup_api_key CRICKETDATA_BASE_URL=https://api.cricapi.com/v1
-
Run migrations:
php artisan migrate
-
Set up cron job (for automatic match updates):
# Add to crontab (runs every 5 minutes) */5 * * * * curl http://localhost/cron
-
Start development server:
php artisan serve
-
Access the application:
- Homepage:
http://localhost:8000 - Practice Mode:
http://localhost:8000/practice
- Homepage:
The cricket API configuration allows you to:
- Set API keys for different providers
- Configure base URLs and endpoints
- Set provider priority order
- Add new API providers easily
Key settings:
baseURL: Used throughout the application for generating URLs- Set via
APP_URLenvironment variable - Defaults to
http://localhost
/- Homepage (shows live matches)/after-start- Match selection page/practice- Practice mode grade selection/practice/play- Practice mode game interface/practice/results- Practice mode results/cron- Automated match data update endpoint/liveScore- AJAX endpoint for live match scores/howzzat- Cricket terminology page/pavilion- Cricket information page
PublicController:
getIndex()- Homepage with live matchesgetafterStart()- Match selection interfacegetDataAuto()- Cron job for match updatesgetliveScore()- AJAX endpoint for scorespostAnswer()- Process game answersconvertMatchIdToInteger()- Match ID conversion utility
PracticeController:
index()- Grade selection pagestart()- Initialize practice sessionplay()- Game interfacesubmitAnswer()- Validate answersresults()- Results display
- Live Match Integration: Real-time cricket match data
- Practice Mode: Standalone math practice without matches
- Multi-Grade Support: Questions for grades 3, 4, and 5
- Fallback API System: Automatic failover between providers
- Automatic Updates: Cron job keeps data fresh
- User Authentication: Login system for tracking scores
- Leaderboards: Score tracking and rankings
- Responsive Design: Works on desktop and mobile devices
The Laravel framework is open-sourced software licensed under the MIT license.