# Mice!

Mice! is a strategic game where players must kill rats with bombs before they reproduce and become too numerous. The game is a clone of the classic game Rats! for Windows 95.

## Compatibility
*It's developed in Python 3.13, please use it*

## Features

- **Maze Generation**: Randomly generated mazes using Depth First Search (DFS) algorithm.
- **Units**: Different types of units such as rats, bombs, and points with specific behaviors.
- **Graphics**: Custom graphics for maze tiles, units, and effects.
- **Sound Effects**: Audio feedback for various game events.
- **Scoring**: Points system to track player progress.
- **Performance**: Optimized collision detection system supporting 200+ simultaneous units using NumPy vectorization.

## Engine Architecture

The Mice! game engine is built on a modular architecture designed for flexibility and maintainability. The engine follows a component-based design pattern where different systems handle specific aspects of the game.

### Core Engine Components

#### 1. **Collision System** (`engine/collision_system.py`)
- **CollisionSystem Class**: High-performance collision detection using NumPy vectorization
- **Features**:
  - Spatial hashing with grid-based lookups (O(1) average case)
  - Support for 6 collision layers (RAT, BOMB, GAS, MINE, POINT, EXPLOSION)
  - Hybrid approach: simple iteration for <10 candidates, NumPy vectorization for ≥10
  - Pre-allocated arrays with capacity management to minimize overhead
  - Area queries for explosion damage (get_units_in_area)
  - Cell-based queries for gas/mine detection (get_units_in_cell)
- **Performance**:
  - Handles 200+ units at ~3ms per frame
  - Reduces collision checks from O(n²) to O(n) using spatial partitioning
  - Vectorized distance calculations for massive parallel processing

#### 2. **Rendering System** (`engine/sdl2.py`)
- **GameWindow Class**: Central rendering manager using SDL2
- **Features**:
  - Hardware-accelerated rendering via SDL2
  - Texture management and caching
  - Sprite rendering with transparency support (SDL_BLENDMODE_BLEND for alpha blending)
  - Text rendering with custom fonts
  - Resolution-independent scaling
  - Fullscreen/windowed mode switching
  - Blood stain rendering with RGBA format and proper alpha channel
- **Optimizations**:
  - Cached viewport bounds to avoid repeated calculations
  - Pre-cached image sizes for all assets at startup
  - Blood overlay layer system (no background regeneration needed)
  - Pre-generated blood stain pool (10 variants) for instant spawning
- **Implementation**:
  - Uses SDL2 renderer for efficient GPU-accelerated drawing
  - Implements double buffering for smooth animation
  - Manages texture atlas for optimized memory usage
  - Handles viewport transformations for different screen resolutions

#### 3. **Input System** (`engine/controls.py`)
- **KeyBindings Class**: Handles all user input
- **Features**:
  - Keyboard input mapping and handling
  - Joystick/gamepad support
  - Configurable key bindings
  - Input state management
- **Implementation**:
  - Event-driven input processing
  - Key state buffering for smooth movement
  - Support for multiple input devices simultaneously
  - Customizable control schemes

#### 3. **Map System** (`engine/maze.py`)
- **Map Class**: Manages the game world structure
- **Features**:
  - Maze data loading and parsing
  - Collision detection system
  - Tile-based world representation
  - Pathfinding support for AI units
- **Implementation**:
  - Grid-based coordinate system
  - Efficient collision detection using spatial partitioning
  - Support for different tile types (walls, floors, special tiles)
  - Integration with maze generation algorithms

#### 4. **Audio System**
- **Sound Management**: Handles all audio playback
- **Features**:
  - Sound effect playback
  - Background music support
  - Volume control
  - Multiple audio channels
- **Implementation**:
  - Uses subprocess module for audio playback
  - Asynchronous sound loading and playing
  - Audio file format support (WAV, MP3, OGG)

### Game Loop Architecture

The main game loop follows an optimized 4-pass pattern:
1. **Pre-Registration Phase**: Populate collision system with unit positions before movement
2. **Update Phase**: Execute unit logic and movement (bombs/gas can now query collision system)
3. **Re-Registration Phase**: Update collision system with new positions after movement
4. **Collision & Render Phase**: Check collisions and draw all game objects

```
Pre-Register → Move → Re-Register → Collisions → Render → Present → Repeat
```

This architecture ensures weapons (bombs, gas) can detect victims during their execution phase while maintaining accurate collision data.

## Units Implementation

The game uses an object-oriented approach for all game entities. Each unit type inherits from a base unit class and implements specific behaviors.

### Base Unit Architecture

All units share common properties and methods:
- **Position and Movement**: 2D coordinates with movement capabilities
- **Unique Identification**: UUID-based unique identifiers
- **Collision Detection**: Bounding box collision system
- **State Management**: Current state tracking (alive, dead, exploding, etc.)
- **Rendering**: Sprite-based visual representation

### Unit Types Implementation

#### 1. **Rat Units** (`units/rat.py`)

**Base Rat Class**:
- **AI Behavior**: Implements pathfinding using A* algorithm
- **Movement**: Grid-based movement with smooth interpolation
- **State Machine**: Multiple states (wandering, fleeing, reproducing)

**Male Rat Class**:
- **Reproduction Logic**: Seeks female rats for mating
- **Territorial Behavior**: Defends territory from other males
- **Lifespan Management**: Age-based death system

**Female Rat Class**:
- **Pregnancy System**: Gestation period simulation
- **Offspring Generation**: Creates new rat units
- **Maternal Behavior**: Protects offspring from threats

**Implementation Details**:
```python
# Optimized rat behavior with pre-calculated render positions
class Rat:
    def move(self):
        self.process_ai()           # Decision making
        self.handle_movement()      # Position updates
        self._update_render_position() # Cache render coordinates
    
    def collisions(self):
        # Use optimized collision system with vectorization
        collisions = self.game.collision_system.get_collisions_for_unit(
            self.id, self.bbox, self.collision_layer
        )
        # Process only Rat-to-Rat collisions
        for _, other_id in collisions:
            other_unit = self.game.get_unit_by_id(other_id)
            if isinstance(other_unit, Rat):
                self.handle_rat_collision(other_unit)
    
    def draw(self):
        # Use cached render positions (no recalculation)
        self.game.render_engine.draw_image(
            self.render_x, self.render_y, self.sprite, tag="unit"
        )
```

#### 2. **Bomb Units** (`units/bomb.py`)

**Bomb Class**:
- **Timer System**: Countdown mechanism before explosion
- **Placement Logic**: Player-controlled positioning
- **Damage Calculation**: Blast radius and damage computation

**Explosion Class**:
- **Visual Effects**: Animated explosion graphics
- **Damage Dealing**: Affects units within blast radius
- **Temporary Entity**: Self-destructs after animation

**Implementation Details**:
- **State Machine**: Armed → Countdown → Exploding → Cleanup
- **Optimized Damage System**: Uses collision_system.get_units_in_area() with vectorized distance calculations
- **Effect Propagation**: Chain reaction support for multiple bombs
- **Area Query Example**:
```python
def die(self):
    # Collect explosion positions
    explosion_positions = self.calculate_blast_radius()
    # Query all rats in blast area using vectorized collision system
    victims = self.game.collision_system.get_units_in_area(
        explosion_positions, 
        layer_filter=CollisionLayer.RAT
    )
    for unit_id in victims:
        rat = self.game.get_unit_by_id(unit_id)
        if rat:
            rat.die()
```

#### 3. **Point Units** (`units/points.py`)

**Point Class**:
- **Collection Mechanics**: Player interaction system
- **Value System**: Different point values for different achievements
- **Visual Feedback**: Pickup animations and effects

### Unit Interaction System

Units interact through a centralized collision and event system:

1. **Collision Detection**: 
   - **Spatial hashing**: Grid-based broad phase with O(1) lookups
   - **NumPy vectorization**: Parallel distance calculations for large candidate sets
   - **Hybrid approach**: Direct iteration for <10 candidates, vectorization for ≥10
   - **Layer filtering**: Efficient collision filtering by unit type (RAT, BOMB, GAS, etc.)
   - **Area queries**: Optimized explosion and gas effect calculations

2. **Event System**:
   - Unit death events
   - Reproduction events
   - Explosion events (with area damage)
   - Point collection events (90 frames lifetime ~1.5s at 60 FPS)

3. **AI Communication**:
   - Shared pathfinding data
   - Pheromone trail system for rat behavior
   - Danger awareness (bombs, explosions)

4. **Spawn Protection**:
   - Rats won't spawn on cells occupied by weapons (mines, bombs, gas)
   - Automatic fallback to adjacent cells if primary position blocked
   - Prevents unfair early-game deaths

## Technical Details

- **Language**: Python 3.13
- **Libraries**: 
    - `numpy` 2.3.4 for vectorized collision detection
    - `sdl2` for graphics and window management
    - `Pillow` for image processing
    - `uuid` for unique unit identification
    - `subprocess` for playing sound effects
    - `tkinter` for maze generation visualization
- **Performance Optimizations**:
    - **Collision System**: NumPy-based spatial hashing reducing O(n²) to O(n)
    - **Rendering Cache**: Pre-calculated render positions, viewport bounds, and image sizes
    - **Blood Overlay**: Separate sprite layer eliminates background regeneration
    - **Hybrid Processing**: Automatic switching between direct iteration and vectorization
    - **Pre-allocated Arrays**: Capacity-based resizing minimizes NumPy vstack overhead
    - **Texture Atlasing**: Reduced memory usage and GPU calls
    - **Object Pooling**: Blood stain pool (10 pre-generated variants)
    - **Delta Time Updates**: Frame rate independence
- **Memory Management**:
    - Automatic cleanup of dead units
    - Texture caching and reuse
    - Efficient data structures for 200+ simultaneous units
    - Blood stain sprite pool to avoid runtime generation

## Environment Variables

- `SDL_VIDEODRIVER`: Set the video driver (x11, wayland, etc.)
- `RESOLUTION`: Set the screen resolution (format: WIDTHxHEIGHT)
- `FULLSCREEN`: Enable/disable fullscreen mode (true/false)
- `SOUND_ENABLED`: Enable/disable sound effects (true/false)

## Installation

1. **Clone the repository**:
        ```bash
        git clone https://github.com/yourusername/mice-maze-game.git
        cd mice-maze-game
        ```
2. **Create a virtual environment**:
        ```bash
        python3 -m venv venv
        source venv/bin/activate
        ```
3. **Install the dependencies**:
        ```bash
        pip install -r requirements.txt
        ```
4. **Run the game**:
        ```bash
        python rats.py
        ```

## Project Structure

```
mice/
├── engine/                     # Core engine components
│   ├── collision_system.py    # NumPy-based vectorized collision detection
│   ├── controls.py            # Input handling system
│   ├── graphics.py            # Blood overlay and rendering optimizations
│   ├── maze.py                # Map and collision system
│   ├── sdl2.py                # Rendering and window management
│   └── unit_manager.py        # Unit spawning and lifecycle management
├── units/                      # Game entity implementations
│   ├── unit.py                # Base unit class with collision layers
│   ├── bomb.py                # Bomb and explosion logic with area damage
│   ├── gas.py                 # Gas weapon with cell-based detection
│   ├── mine.py                # Proximity mine with trigger system
│   ├── rat.py                 # Rat AI with optimized rendering cache
│   └── points.py              # Collectible points (90 frames lifetime)
├── assets/                    # Game resources
│   ├── images/                # Sprites and textures
│   └── fonts/                 # Text rendering fonts
├── sound/                     # Audio files
├── maze.py                    # Maze generation algorithms
├── rats.py                    # Main game entry point with 4-pass game loop
├── requirements.txt           # Python dependencies (including numpy)
├── .env                       # Environment configuration
└── README.md                  # This documentation
```

## Game Files Details

- `maze.py`: Contains the `MazeGenerator` class implementing DFS algorithm for procedural maze generation
- `rats.py`: Main game controller with 4-pass optimized game loop, manages collision system and unit lifecycle
- `engine/collision_system.py`: NumPy-based spatial hashing system supporting 200+ units at 3ms/frame
- `engine/graphics.py`: Blood overlay system with pre-generated stain pool and rendering optimizations
- `engine/controls.py`: Input abstraction layer with configurable key bindings
- `engine/maze.py`: World representation with collision detection and pathfinding support
- `engine/sdl2.py`: Low-level graphics interface wrapping SDL2 with alpha blending and texture caching
- `engine/unit_manager.py`: Centralized unit spawning with weapon collision avoidance
- `units/unit.py`: Base unit class with collision layer support
- `units/bomb.py`: Explosive units with vectorized area damage calculations
- `units/gas.py`: Area denial weapon using cell-based victim detection
- `units/mine.py`: Proximity-triggered explosives
- `units/rat.py`: AI-driven entities with cached render positions and collision filtering
- `units/points.py`: Collectible scoring items (90 frame lifetime, ~1.5s at 60 FPS)
- `assets/`: Game resources including sprites, textures, and fonts
- `sound/`: Audio assets for game events and feedback
- `scores.txt`: Persistent high score storage
- `.env`: Runtime configuration and environment settings
- `.gitignore`: Version control exclusion rules

