Skip to main content

rsnaker/
lib.rs

1#![forbid(unsafe_code)]
2#![deny(clippy::all)]
3#![deny(clippy::pedantic)]
4#![allow(clippy::missing_panics_doc)]
5// Documentation for all Clippy lints: https://github.com/rust-lang/rust-clippy/
6//! # Snake Game using Ratatui
7//!
8//! This module implements a terminal-based snake game using the Ratatui crate for rendering.
9//!
10//! ## Features
11//! - **Terminal UI**: Uses Ratatui for rendering a grid-based game.
12//! - **Game Logic**: Manages snake movement, collisions, and scoring.
13//! - **Multithreading**: Uses multiple threads for input handling, rendering at 60 FPS, and game logic execution.
14//! - **Emoji-based graphics**: Supports rendering the snake using emojis instead of ASCII.
15//! - **Configurable parameters**: With `clap` for command-line arguments.
16//!
17//! ## References
18//! - Clippy lints: <https://github.com/rust-lang/rust-clippy/>
19//! - Ratatui tutorial: <https://ratatui.rs/tutorials/hello-ratatui/>
20//! - Example: <https://ratatui.rs/examples/widgets/canvas/>
21//!
22//! ## Architecture
23//! - Uses `RwLock` for synchronization.
24//! - Spawns separate threads for input handling, rendering (60Hz), and game logic execution.
25//! - For more details, see [ARCHITECTURE.md](https://github.com/FromTheRags/rsnake/blob/main/ARCHITECTURE.md).
26//!
27//! ## Documentation generation
28//! - `cargo doc --document-private-items --no-deps --open`
29//!
30//! ## Tests
31//!  - As usual, run them with `cargo test` the project is set up with a lib containing all the code, and a main.rs just calling it
32//!  - As this is a widespread pattern providing full compliance with the Rust test ecosystem, allowing doc comment to be automatically tested, for example.
33//!    For more details, see [readme.md](https://github.com/FromTheRags/rsnake/blob/main/README.md)
34
35pub mod controls;
36pub mod game_logic;
37pub mod graphics;
38
39use crate::game_logic::logger::log_configuration::{
40    DEFAULT_LOG_CONFIG_PATH, LogLevel, init_logger, update_log_level,
41};
42use crate::game_logic::playing_thread_manager::Game;
43use clap::Parser;
44use game_logic::game_options::GameOptions;
45use tracing::{debug, info};
46
47/// # Panics
48/// If bad characters (invalid size) are provided for snake body or head
49pub fn start_snake() {
50    // get command line options and parsed them to check for errors (auto using value parser in clap)
51    let mut args = GameOptions::parse();
52    let cli_random = args.random;
53    //println!("{}", args.to_structured_toml());
54    //load args from the already saved preset if its user choice
55    if let Some(preset) = args.load {
56        args = GameOptions::load_from_toml_preset(preset).unwrap_or_else(|_| {
57            panic!("Fail to load Snake configuration file for preset {preset}")
58        });
59    }
60    if cli_random {
61        let previous_log_level = args.log_level;
62        let previous_load = args.load;
63        args = GameOptions::random();
64        args.log_level = previous_log_level;
65        args.load = previous_load;
66    }
67
68    // Initialize logger: configuration (level, file name, time format and all
69    // formatting booleans) is read from a dedicated TOML file inside `init_logger`.
70    let (_guard, log_config) = init_logger(Some(DEFAULT_LOG_CONFIG_PATH));
71    // CLI log level (if explicitly set, i.e., not Off) overrides the file level.
72    if args.log_level != LogLevel::Off {
73        update_log_level(args.log_level);
74    }
75    info!("Snake game arguments parsed and configuration is successful!");
76    debug!(log_config = ?log_config);
77    // If everything is OK, inits terminal for rendering
78    let terminal = ratatui::init();
79
80    // init our own Game engine and a display greeting screen
81    Game::menu(args, terminal);
82
83    //in all cases, restore
84    ratatui::restore();
85}