Skip to content

ovation22/TripleDerby

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

67 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CI MIT license

Triple Derby

A modern horse racing simulation built with .NET Aspire, .NET 10 Web API, and Blazor.

Triple Derby is a management and simulation game where players breed, train, feed, and race virtual horses — each with unique genetics and performance characteristics. This modern rebuild uses .NET 10, Blazor, and .NET Aspire to orchestrate a clean, extensible architecture.


🚀 Features

  • Modern .NET 10 Web API for all gameplay operations
  • Blazor Admin UI for testing, debugging, and management
  • .NET Aspire orchestration for local infrastructure and future cloud deployment
  • Message-driven breeding pipeline with a background worker (TripleDerby.Services.Breeding / BreedingRequestProcessor) and transactional foal creation
  • Breeding engine implementing Punnett-style dominant/recessive genetics and a weighted mutation system
  • Weighted color rarity selection and leg-type influenced racing behavior
  • Advanced racing simulation with:
    • Tick-based movement with modifier pipeline (Stats → Environment → Phase → Stamina → Random)
    • Five distinct leg types with strategic advantages (phase-based timing and conditional bonuses)
    • Stamina depletion system affecting performance over race distance
    • Track condition modifiers (11 conditions from Fast to Frozen)
    • Surface effects (Dirt, Turf, Artificial)
    • Lane positioning and traffic detection
  • Distributed caching for featured parent lists and performance-sensitive reads
  • Message broker support (RabbitMQ) for message-driven workflows and background processing
  • Training, feeding, and month-end lifecycle processing
  • Health checks, graceful cancellation handling, and robust error handling for background workers and API
  • Easily extensible to microservices, background workers, and cloud deployment

🏛️ Solution Structure

Included in the solution:

  • .NET 10 Web Api
  • Blazor Admin UI
  • .NET Aspire orchestration
  • Logging
  • Global Exception Handling
  • Cancellation Handling
  • Health Checks
  • CI Pipelines
  • Unit Tests
  • Worker Service(s) (e.g., Breeding & Racing Simulation)
  • Distributed Caching (IDistributedCacheAdapter)
  • Message Broker Support (RabbitMQ)
  • Integration Tests
  • Benchmark Tests
  • Architectural Tests

🧩 Architecture Overview

graph TD
    A{API Project} --> B[Core Project]
    C[Infrastructure Project] --> B
    A --> C
    E[Shared Kernel] --> B
    A --> E
    C --> E

    subgraph "API Layer"
      A[TripleDerby.Api<br>• Controllers<br>• Configuration<br>• Program.cs]
    end

    subgraph "Core Layer"
      B[TripleDerby.Core<br>• Entities<br>• Interfaces<br>• Domain Services]
    end

    subgraph "Shared Kernel"
      E[TripleDerby.SharedKernel<br>• DTOs<br>• Base Classes<br>• Value Objects<br>• Common Interfaces<br>• Events]
    end

    subgraph "Infrastructure Layer"
      C[TripleDerby.Infrastructure<br>• Repositories<br>• Http Clients<br>• Event Producers]
    end

    style A fill:#0078d7,stroke:#004578,stroke-width:1px,color:white
    style B fill:#28a745,stroke:#115724,stroke-width:1px,color:white
    style C fill:#ff9900,stroke:#cc7a00,stroke-width:1px,color:white
    style E fill:#8a2be2,stroke:#5a189a,stroke-width:1px,color:white
Loading

🖥️ System Flow

flowchart TD

A[Player Action] --> B{Choose Activity}

B -->|Breed| C[Select Sire & Dam]
C --> D[Compute Genetics & Stats]
D --> E[Foal Created + Naming]

B -->|Train| F[Select Training Routine]
F --> G[Apply Stat Changes]
G --> H[Injury Check]

B -->|Feed| I[Pick Feed Type]
I --> J[Apply Happiness/Stat Effects]

B -->|Race| K[Select Track/Jockey/Plan]
K --> L[Race Simulation Engine]
L --> M[Outcome + Injury Check]

M --> N[Month-End Processing]
N --> O[Stipend + Reset AP + Reset Happiness]
Loading

📦 Domain Model Overview

classDiagram
    class Horse {
        Guid Id
        string Name
        Gender Gender
        Color Color
        LegType LegType
        Stats GeneticDominant
        Stats GeneticRecessive
        Stats ActualStats
        int Happiness
        int Age
        int RacesThisYear
    }

    class Stats {
        int Speed
        int Stamina
        int Agility
        int Durability
    }

    class BreedingService {
        +Breed(sire, dam) Horse
        +AssignColor()
        +AssignGender()
        +AssignLegType()
        +ComputeGenetics()
        +ApplyMutation()
        +ComputeActualStats()
    }

    class TrainingService {
        +Train(horse, routine)
        +ApplyEffects()
        +CheckInjury()
    }

    class FeedingService {
        +Feed(horse, feedType)
    }

    class RacingService {
        +SimulateRace(horse, conditions, plan)
        +ComputeDistancePerTick()
        +LaneModifiers()
        +ConditionModifiers()
        +OvertakeLogic()
    }

    class Stable {
        Guid OwnerId
        List~Horse~ Horses
    }

    Horse --> Stable : "belongs to"
    BreedingService --> Horse
    TrainingService --> Horse
    FeedingService --> Horse
    RacingService --> Horse
    Horse --> Stats : "uses"
Loading

🧬 Gameplay Systems Summary

Breeding

Breeding creates a new foal influenced by parent traits:

  • Select CPU or stable-owned sire/dam
  • Weighted color selection (with special colors)
  • Leg type influences racing behavior
  • Dominant/Recessive stats computed using Punnett-style quadrants
  • Final step: player names the foal
sequenceDiagram
  participant Player
  participant BreedingController
  participant BreedingService
  participant Repository
  participant MessagePublisher
  participant MessageBus
  participant BreedingRequestProcessor
  participant RNG as RandomGenerator
  participant NameGen as HorseNameGenerator

  Player->>BreedingController: POST /api/breeding/requests (BreedRequest)
  BreedingController->>BreedingService: Breed(request)
  BreedingService->>Repository: Create BreedingRequest (Status=Pending)
  Repository-->>BreedingService: BreedingRequest(created)
  BreedingService->>MessagePublisher: Publish BreedingRequested(Event)
  MessagePublisher->>MessageBus: Send BreedingRequested
  MessageBus-->>BreedingRequestProcessor: Deliver BreedingRequested

  BreedingRequestProcessor->>Repository: Find BreedingRequest(id)
  Repository-->>BreedingRequestProcessor: BreedingRequest(entity)
  BreedingRequestProcessor->>Repository: Update BreedingRequest (Status=InProgress) — claim
  BreedingRequestProcessor->>Repository: Get Parent: Dam
  Repository-->>BreedingRequestProcessor: Dam
  BreedingRequestProcessor->>Repository: Get Parent: Sire
  Repository-->>BreedingRequestProcessor: Sire

  BreedingRequestProcessor->>RNG: GetRandomGender / LegType / Color / Stats
  RNG-->>BreedingRequestProcessor: Random values
  BreedingRequestProcessor->>NameGen: Generate()
  NameGen-->>BreedingRequestProcessor: FoalName

  Note right of Repository: ExecuteInTransaction:<br>- Create Foal<br>- Update parented counters<br>- Update BreedingRequest (FoalId, Status=Completed, ProcessedDate)
  BreedingRequestProcessor->>Repository: Execute transaction (create foal & update)
  Repository-->>BreedingRequestProcessor: Foal(created)

  BreedingRequestProcessor->>MessagePublisher: Publish BreedingCompleted(Event)
  MessagePublisher->>MessageBus: Send BreedingCompleted
  MessageBus-->> Consumers: Deliver BreedingCompleted

  alt Publish failure after commit
    BreedingRequestProcessor->>Repository: Persist FailureReason (keep Status=Completed)
    Repository-->>BreedingRequestProcessor: Ack
  end
Loading

Training

  • May increase stats
  • May increase happiness
  • Reduced effect if recently injured
  • Small chance of injury

Feeding

  • Affects happiness
  • Can influence training effectiveness
  • May add minor stat variance

Racing

Race outcome depends on:

  • Track selection (surface, distance, conditions)
  • Horse stats (Speed, Agility, Stamina, Durability)
  • Leg type with distinct strategies:
    • FrontRunner: Early race advantage (0-20%)
    • StartDash: Opening quarter burst (0-25%)
    • StretchRunner: Stretch run power (60-80%)
    • LastSpurt: Closing kick (75-100%)
    • RailRunner: Lane 1 bonus with clear path (conditional)
  • Stamina system: Depletes based on distance, pace, and horse efficiency
  • Environmental modifiers:
    • Surface effects (Dirt, Turf, Artificial)
    • 11 track conditions (Fast, Firm, Good, WetFast, Soft, Yielding, Muddy, Sloppy, Heavy, Frozen, Slow)
  • Modifier pipeline: Base Speed × Stats × Environment × Phase × Stamina × Random
  • Lane positioning and traffic detection
  • Injury chance after each race
  • Max 8 races per year, max 3-year racing career

Month-End

  • Player receives stipend
  • Action points reset
  • Happiness resets to 50

▶️ Running the Project

Prerequisites

  • .NET 10 SDK
  • Docker Desktop (for Aspire dependencies)
  • VS 2026, or VS Code + C# Dev Kit

Start the Full System via Aspire

dotnet run --project ./TripleDerby.AppHost

Aspire launches:

  • TripleDerby API
  • Blazor Admin UI
  • Database or other configured services
  • Aspire dashboard with logs + health checks

Create Racers

Seed the database with Racers with the following command:

cd .\tools\BreedingSeeder\
dotnet run

Follow the on-screen prompts. Defaults are fine.


🛠️ Development Notes

  • Keep gameplay logic in domain services for clean, testable architecture
  • Use deterministic RNG for reproducible breeding and racing tests
  • Use DTOs to avoid leaking domain internals
  • Future expansions:
    • Breeding Worker
    • Racing Simulation Worker
    • Month-End Scheduler
  • Consider messaging (RabbitMQ or Service Bus) for async workload distribution

Solution Structure

Core Project

The Core project is the center of the Clean Architecture design, and all other project dependencies should point toward it. As such, it has very few external dependencies. The Core project should include things like:

  • Entities
  • DTOs
  • Interfaces
  • Domain Services

Infrastructure Project

Most of your application's dependencies on external resources should be implemented in classed defined in the Infrastructure project. These classed should implement interfaces defined in Core. The Infrastructure project should include things like:

  • Http clients
  • Repositories
  • Event Hub Producer clients
  • Service Bus clients

Api Project

The entry point of the application is the Api project. The Api project should include things like:

  • Program.cs
  • Controllers
  • Configurations

Test Projects

Test projects are organized based on the kind of test (unit, integration, benchmark, etc.).

Unit Tests

Unit tests provide a way to verify and validate functionality of individual methods/components/features. This project contains example tests using xUnit.

Integration Tests

Integration testing provides a way to ensure that an application's components function correctly at each level.

Architectural Tests

Architectural rules can be enforced using NetArchTest, a fluent API for .NET Standard that can enforce architectural rules within unit tests.

Benchmark Tests

Benchmark testing is provided by BenchmarkDotNet, a powerful .NET library for creating and executing benchmark tests.

dotnet run --project ./tests/Api.Project.Template.Tests.Benchmark -c Release

🗺️ Roadmap

Short Term

  • Complete race engine visualization
  • Expand Admin UI tooling
  • Add stable management

Long Term

  • Worker/microservice separation
  • In-game marketplace
  • Public player UI

About

The online horse racing game!

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •  

Languages