A classic Snake game implementation in C using the ncurses library for terminal-based graphics.
This is a terminal-based Snake game where the player controls a growing snake that must eat food while avoiding collisions with walls and its own body. The game features smooth movement, collision detection, and a simple restart mechanism.
- Terminal-based graphics using ncurses
- Smooth snake movement with configurable speed (10 movements per second)
- Collision detection for walls and self-collision
- Dynamic snake growth when eating food
- Scoring system with live score display and persistent high score tracking
- High score persistence stored in
files/high_score.txt, survives game restarts - Game restart functionality after collision
- Keyboard controls supporting both arrow keys and vim-style movement keys
- Terminal resize support — the game window re-centers automatically on resize
- Minimum terminal size enforcement at startup and on resize events
-
ncurses - Terminal user interface library
- Used for rendering the game window and handling keyboard input
- Installation:
- Ubuntu/Debian:
sudo apt-get install libncurses5-dev libncursesw5-dev - Fedora/RHEL:
sudo dnf install ncurses-devel - macOS:
brew install ncurses
- Ubuntu/Debian:
-
cvector - Custom external vector library
- A custom dynamic array implementation for managing snake segments
- Note: This is referenced in
game.has<vector.h>- you need to have this library installed or available in your include path - The library must provide functions like:
init_void_vector,void_append,void_get,void_set,free_void_vector
- CMake (version 3.15 or higher)
- C Compiler with C99 support or later
- Address Sanitizer support (enabled via
-fsanitize=address)
-
Clone the repository:
git clone https://github.com/Lunaaaalj/snake_game.git cd snake_game -
Create a build directory:
mkdir build cd build -
Configure with CMake:
cmake ../src
-
Build the executable:
make
-
Run the game:
./snake
The game supports two control schemes:
- ↑ (Up Arrow) - Move up
- ↓ (Down Arrow) - Move down
- ← (Left Arrow) - Move left
- → (Right Arrow) - Move right
- k - Move up
- j - Move down
- h - Move left
- l - Move right
- q - Quit the game
-
Starting the game: The snake starts in the center of the screen with an initial length of 3 segments (1 head + 2 body segments).
-
Movement: The snake moves continuously in the current direction. You can change direction using the control keys, but you cannot reverse directly into yourself (e.g., if moving right, you cannot immediately move left).
-
Eating food:
- Food is represented by the
*character - When the snake's head reaches the food position, the snake grows by one segment
- New food appears at a random location after being eaten
- Food is represented by the
-
Collision:
- The game ends when the snake collides with:
- The window borders
- Its own body segments
- Upon collision, the snake turns into
Xcharacters - The current score is shown; if a new high score was reached, "New Highest Score" is displayed
- The game ends when the snake collides with:
-
Restarting:
- After a collision, press Enter to restart the game
- Press q to quit the game
- Window size: 20 rows × 35 columns (centered in the terminal, adapts on resize)
- Snake representation:
- Head:
# - Body segments:
# - When collided:
X
- Head:
- Food representation:
* - Score display: shown at the bottom center of the window during play
- Title: "Snake" displayed at the top center of the window
The game consists of four main files:
- game.h - Header file with function declarations and data structures
- game.c - Implementation of game logic functions
- main.c - Main game loop and initialization
- files/high_score.txt - Persistent storage for the high score
-
coord: Structure representing x,y coordinatestypedef struct coord { int x_pos; int y_pos; } coord;
-
snk_state: Enum representing snake directiontypedef enum snk_state { SNK_UP, SNK_DOWN, SNK_LEFT, SNK_RIGHT, SNK_NAN } snk_state;
CheckInput(): Processes keyboard input and updates the requested snake direction; also handles terminal resize eventsmove_snk(): Updates snake position based on current directionupdate_scr(): Renders the game state (snake, food, score) to the screensnake_food_gen(): Generates random food positions, guaranteed not to overlap the snake bodysnake_grow(): Adds a new segment to the snakesnk_collided(): Detects collisions with walls or selfhandle_resize(): Handles terminal resize events — re-centers the game window and returnsfalseif the terminal is now too smallget_high_score(): Reads the high score fromfiles/high_score.txtwrite_high_score(): Writes the current high score tofiles/high_score.txtdisp_hscore(): Displays "New Highest Score" at the bottom of the window after a collisionterminate_session(): Cleanly exits the game
The main game loop operates at 10 movements per second (100ms interval):
- Check for keyboard input (including resize events)
- Update snake position every 100ms
- Check for food collision and grow snake + increment score if needed
- Update and persist high score if beaten
- Check for wall/self collision
- Update screen rendering (score shown at the bottom)
- Handle game over and restart logic
- The game uses a dynamic vector (
void_vec) to store snake segment positions - Memory is properly freed and reinitialized on game restart
- Address Sanitizer is enabled during compilation to detect memory issues
-
Fixed window size: The game window is hardcoded to 20×35 characters; the window is re-centered on resize but its dimensions do not change
-
External dependency: Requires the custom
cvectorlibrary which is not included in the repository. Users must install or provide this library separately. -
No speed increase: Game speed remains constant regardless of snake length
-
Terminal size: If your terminal is smaller than the minimum required size (37 columns × 22 rows), the game will exit with an error message at startup or during a resize event.
-
Curses initialization: The game assumes ncurses is properly installed and functional on your system
-
Minimum terminal size: Ensure your terminal window is at least 37 columns × 22 rows to display the game
- Use a terminal with at least 37 columns × 22 rows for optimal display
- Ensure the
cvectorlibrary is properly installed before building
The code is formatted using clang-format with LLVM conventions (as noted in main.c).
The project is compiled with Address Sanitizer (-fsanitize=address) to help detect:
- Memory leaks
- Buffer overflows
- Use-after-free errors
- Other memory-related issues
No license information is currently provided in the repository.
This appears to be a personal/educational project. If you'd like to contribute, consider:
- Adding a proper
cvectorlibrary or replacing it with a standard implementation - Implementing difficulty levels with increasing speed
- Implementing terminal size detection and adaptive window sizing
- Adding color support for better visuals
- Scoring: The player now earns one point for each food item eaten. The current score is displayed at the bottom center of the game window during play.
- High score persistence: The highest score achieved is stored in
files/high_score.txtand persists across sessions. The file is updated immediately when the current score exceeds the stored high score. - New Highest Score notification: When a collision ends the game and the player has beaten the previous high score, a "New Highest Score" message replaces the score line at the bottom of the window.
- Food collision fix:
snake_food_gen()now re-rolls the food position if it overlaps any segment of the snake, ensuring food always spawns on a free cell.
- Classic Snake gameplay in a 20×35 terminal window using ncurses
- Arrow key and vim-style (h/j/k/l) controls
- Self-collision and wall-collision detection
- Dynamic snake growth on eating food
- Terminal resize handling — game window re-centers automatically; exits gracefully if the terminal becomes too small (minimum 37 × 22)
- Minimum terminal size validation at startup
- Address Sanitizer enabled in debug builds
- Built with ncurses for terminal graphics
- Uses a custom vector implementation for dynamic array management