A classic Snake game implemented in TypeScript with both Object-Oriented Programming (OOP) and Functional Programming (FP) paradigms. This project allows you to switch between implementations to compare the differences and similarities between these two programming approaches.
The project is organized into two main implementations:
src/
├── oop/ # OOP implementation
│ ├── core/ # OOP implementation core
│ ├── entities/ # OOP implementation entities
│ ├── ui/ # OOP implementation UI components
│ ├── utils/ # OOP implementation utilities
│ └── config/ # OOP implementation configuration
├── functional/ # Functional implementation
│ ├── core/ # FP core logic
│ ├── entities/ # FP entities (conceptual)
│ ├── ui/ # FP UI components
│ ├── utils/ # FP utilities
│ └── config/ # FP configuration
├── factory.ts # Factory for switching implementations
├── main.ts # Entry point
└── style.css # Styling
The OOP implementation follows a component-based architecture with clear separation of concerns:
-
Game Class (
core/Game.ts
): Central controller that manages the game loop, state, and coordinates between components. -
Entities:
Snake
(entities/Snake.ts
): Manages snake movement, growth, and collision detection.Food
(entities/Food.ts
): Handles food generation and detection of when it's eaten.
-
UI Components:
Renderer
(ui/Renderer.ts
): Handles all canvas rendering.InputHandler
(ui/InputHandler.ts
): Manages keyboard input and button events.
- Component-Based Architecture: Each part of the game is encapsulated in its own class with specific responsibilities.
- Dependency Injection: Components receive their dependencies through constructors.
- Observer Pattern: For handling events and communication between components.
- State Management: Game state is managed centrally but accessed through appropriate interfaces.
The functional implementation follows FP principles with pure functions and immutable data:
-
Game State (
functional/core/game.ts
): Defines the game state and pure functions to transform it. -
Pure Functions:
- State transformation functions that take the current state and return a new state.
- UI rendering functions that take state and produce visual output.
- Helper functions for calculations and validations.
-
Side Effects:
- Isolated in specific areas (DOM manipulation, event handling).
- Clearly separated from pure logic.
- Pure Functions: Functions that don't have side effects and always return the same output for the same input.
- Immutability: State is never modified directly; instead, new state is created based on the old state.
- Function Composition: Building complex behavior by combining simpler functions.
- Higher-Order Functions: Functions that take other functions as arguments or return functions.
- Natural modeling of game entities with state and behavior
- Encapsulation of implementation details
- Clear organization of code into logical units
- Familiar to many developers
- Easier to reason about state changes
- Better testability of pure functions
- Reduced bugs from unexpected state mutations
- More declarative code style
- Clone the repository
- Install dependencies:
npm install
- Run the development server:
npm run dev
- Choose between OOP and FP implementations in the UI
- Build for production:
npm run build
- Use arrow keys or WASD to control the snake
- Eat food to grow and earn points
- Avoid hitting walls or yourself
- Press the Restart button to start a new game
If you're new to functional programming, here are some resources to help you understand the FP implementation:
- Functional Programming in JavaScript
- Professor Frisby's Mostly Adequate Guide to Functional Programming
- Functional-Light JavaScript
- Add difficulty levels
- Implement high score tracking
- Add mobile touch controls
- Create power-ups and obstacles