Skip to content

krasimirnyv/Snake-Game-with-custom-DI-Framework

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

10 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐Ÿ Snake Game with Custom DI Framework

Implementation of the classic Snake game in C#, built on top of a custom-made Dependency Injection framework.

Project: Snake Game with Custom Dependency Injection Framework is a console-based implementation of the classic Snake game, built entirely in C#. Besides gameplay, the project showcases a handcrafted DI container (EasyInjector) to demonstrate IoC, constructor injection, and attribute-based field injection.

Snake Game Screenshot


๐Ÿ’ป Link to the Source Code

You can view the source code for this project here:


๐Ÿ“Œ Project Goals

  • Implement a playable Snake console game in C# / .NET.
  • Design and integrate a custom DI framework (no external DI libs).
  • Practice clean code, modularity, and architecture patterns.
  • Persist the highest score between sessions in a user-friendly, cross-platform way.

Game features:

  • Player-controlled snake (arrow keys).
  • Randomly spawning food with different point values.
  • Collision detection (walls & self).
  • Ability for the player to restart or quit after the game ends.
  • Live score and persistent High Score (JSON storage).

โœ… My Solution

Gameplay & Rendering

  • Efficient console rendering via Console.SetCursorPosition.
  • Clear separation of contracts (interfaces) and implementations:
    • IRenderer โ†’ ConsoleRenderer
    • IGameInput โ†’ ConsoleGameInput
    • IRandomGenerator โ†’ RandomGenerator
    • IDateTimeProvider โ†’ SystemDateTimeProvider

High Score Persistence

  • File: highScore.json, stored under the userโ€™s Application Data directory
    • Windows: %AppData%\SnakeGame\highScore.json
    • macOS: ~/Library/Application Support/SnakeGame/highScore.json
    • Linux: ~/.config/SnakeGame/highScore.json
  • Safe, atomic writes (temporary file + replace), thread-safe lock, and in-memory cache.
  • Class: HighScoreService (uses injected IDateTimeProvider).

DI Integration in Program.cs

// SnakeGame/SnakeGame.cs
Injector
    .Register<IRenderer, ConsoleRenderer>()
    .Register<IGameInput, ConsoleGameInput>()
    .Register<IRandomGenerator, RandomGenerator>()
    .Register<IDateTimeProvider, SystemDateTimeProvider>()
    .Create<Engine>()
    .Run(); 

๐Ÿ“‹ Input and Output

Controls

  • โ†‘ Up
  • โ†“ Down
  • โ† Left
  • โ†’ Right

  • โ†ต Enter Restart game
  • โฃ Space Exit game

Output

  • Live rendering of walls, snake, and food in the console.
  • Real-time score & High Score.
  • Game-over screen with optional โ€œNew High Score!โ€ indicator when applicable.

๐Ÿ“Š Solution Design

Component Responsibility
Core/Engine.cs Main game loop (update & render), score, collisions
Models/Snake.cs Snake body, movement, growth
Models/Food*.cs (Star, Sun, Asterisk) Food variants with points & glyphs
IO/ConsoleRenderer.cs Drawing walls, snake, food, score, messages
IO/ConsoleGameInput.cs Non-blocking key input โ†’ Direction
Utility/HighScoreService.cs Load/Save persistent high score (JSON)
Utility/RandomGenerator.cs Random numbers for food placement ans food variants
Contracts/*.cs IRenderer, IGameInput, IRandomGenerator, IDateTimeProvider
DI: CustomDIFramework/* EasyInjector (container, API, attributes, messages)

๐Ÿ”ง Custom DI Framework (EasyInjector)

A lightweight DI framework implemented from scratch in EasyInjector, designed to be reusable and easily integrated into future projects beyond the Snake Game.

Main Types

  • DependencyProvider: the container holding registrations & creating instances.
  • Injector: static fluent entrypoint to build and chain registrations easily.
  • InjectAttribute: opt-in field injection for private instance fields.
  • Dependency: internal wrapper for registrations (instance / type / factory).
  • Utility/ExceptionMessage: centralized error messages.

Registration API

// Generic: interface โ†’ implementation (transient)
provider.Register<IService, Service>();

// Generic: interface โ†’ instance (singleton-like)
provider.Register<IClock>(new SystemClock());

// Generic: interface โ†’ factory (transient via factory)
provider.Register<IRepository, Repository>(p => new Repository(p));

// Non-generic overloads are available too
provider.Register(typeof(IService), typeof(Service));
provider.Register(typeof(IService), new Service());
provider.Register(typeof(IService), (Func<DependencyProvider, object>)(p => new Service()));

Resolution & Object Graph Creation

  • Constructor injection with exactly one public instance constructor:
    • The container inspects the single public constructor, resolves its parameters, and calls it.
    • Each parameter must be registered; otherwise throws a clear exception.
  • Field injection via [Inject] on private instance fields:
    • After construction, the container scans non-public, non-static instance fields, finds those with [Inject], resolves them, and sets values via reflection.
  • Interfaces:
    • Create<T>() / Create(Type):
      • If T is an interface, the container must have a registration and returns the resolved dependency.
      • If T is a class, it must have exactly one public constructor; DI resolves its parameters recursively.

Snippet from usage:

var provider = new DependencyProvider();
provider.Register<IRenderer, ConsoleRenderer>()
        .Register<IGameInput, ConsoleGameInput>()
        .Register<IRandomGenerator, RandomGenerator>()
        .Register<IDateTimeProvider, SystemDateTimeProvider>();

var engine = provider.Create<Engine>(); // ctor-injected: IRenderer, IGameInput, IRandomGenerator, IDateTimeProvider
engine.Run();

Lifetime Semantics

  • Instance registration โ†’ singleton-like (always returns the same object).
  • Type / Factory registration โ†’ transient (new instance per resolve).

Validation & Errors (selected)

  • Duplicate registration for the same abstraction โ†’ invalid.
  • Resolving unregistered abstractions or dependencies โ†’ invalid (clear message).
  • Classes with 0 or >1 public constructors โ†’ invalid (explicit errors).

Limitations (by design for learning)

  • No scopes / disposal / decorators.
  • No cyclic dependency detection (would cause recursion issues).
  • One public constructor rule (keeps resolution deterministic & simple).
  • Field injection supports instance private fields only (no static | no properties).

๐Ÿ“ˆ Dependency Graph

graph TD
    Engine --> IRenderer
    Engine --> IGameInput
    Engine --> IRandomGenerator
    Engine --> IDateTimeProvider

    IRenderer --> ConsoleRenderer
    IGameInput --> ConsoleGameInput
    IRandomGenerator --> RandomGenerator
    IDateTimeProvider --> SystemDateTimeProvider
Loading

๐Ÿ› ๏ธ Technologies Used

  • C# & .NET
  • System.Text.Json (serialization for high score)
  • Console API (rendering)
  • Custom DI (EasyInjector)

โš™๏ธ Prerequisites

To run the project locally, you need:

Verify installation:

dotnet --version
git --version

๐Ÿ“ฅ Clone Repository

Clone the project locally:

git clone https://github.com/krasimirnyv/Snake-Game-with-custom-DI-Framework.git
cd Snake-Game-with-custom-DI-Framework

โ–ถ๏ธ Getting Started

# from repository root
dotnet build
dotnet run --project SnakeGame/SnakeGame.csproj

๐ŸŽฎ Gameplay Preview

Snake Game Console Screenshot


๐Ÿš€ Try the Demo

You can play the game directly in your web browser here (it doesn't contain the DI container):

Play Button

๐Ÿงช Notes & Tips

  • On Unix terminals, avoid forcing console window size; prefer reading Console.WindowWidth/Height.
  • HighScoreService uses an injected IDateTimeProvider โ†’ easy to unit-test with a fake time source.
  • The DI container supports factory registrations, so you can wire complex graphs without external libraries.

๐Ÿ“„ License

This project is licensed under the MIT License.

You are free to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, provided that the copyright notice and this permission notice are included in all copies or substantial portions of the Software.

See the LICENSE file for the full text.

About

Implementation of the classic Snake game in C#, built on top of a custom-made Dependency Injection framework.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages