Implementing Snake Direction Control and Initial Growth in Linux Environment

Direction Input Handling on Linux Unlike Windows' getch(), Linux requires terminal configuration modifications to handle non-blocking keyboard input. Using termios structure settings enables real-time direction input detection:

int Game::input() {
    struct termios terminalSettings, modifiedSettings;
    tcgetattr(STDIN_FILENO, &terminalSettings);
    modifiedSettings = terminalSettings;
    modifiedSettings.c_lflag &= ~ICANON;
    modifiedSettings.c_cc[VTIME] = 0;
    modifiedSettings.c_cc[VMIN] = 1;
    
    tcsetattr(STDIN_FILENO, TCSANOW, &modifiedSettings);
    char keyInput = getchar();
    tcsetattr(STDIN_FILENO, TCSANOW, &terminalSettings);

    switch(keyInput) {
        case 'w': return DIRECTION_UP;
        case 's': return DIRECTION_DOWN;
        case 'a': return DIRECTION_LEFT;
        case 'd': return DIRECTION_RIGHT;
    }
    return -1;
}

Game Loop Architecture The game loop separates input handling and movement logic using pthreads:

void* Game::inputThreadHandler(void* context) {
    Game* gameInstance = static_cast<Game*>(context);
    while(!gameInstance->_exitFlag) {
        gameInstance->processInput();
    }
    return nullptr;
}

int Game::startGameLoop() {
    pthread_t inputThread;
    pthread_create(&inputThread, nullptr, inputThreadHandler, this);

    while(!_exitFlag) {
        updateSnakePosition();
        renderFrame();
        usleep(100000); // 100ms frame rate
    }
    return 0;
}

Snake Growth Mechanics The snake's body management system implements chained node allocation:

int Snake::initialize(char icon, int direction, int length, Coordinate startPos) {
    _head.icon = icon;
    _head.direction = direction;
    _head.position = startPos;
    _head.next = nullptr;
    _size = 1;

    // Build initial body segments
    for(int i = 1; i < length; i++) {
        addBodySegment(icon);
    }
    return 0;
}

int Snake::addBodySegment(char icon) {
    SnakeSegment* newSegment = new SnakeSegment();
    newSegment->icon = icon;
    newSegment->next = _head.next;
    _head.next = newSegment;
    _size++;
    return 0;
}

Movement Implementation Core movement logic handles both head and body segment updates:

void Snake::moveForward() {
    // Store current head position
    Coordinate oldPosition = _head.position;
    char oldIcon = _head.icon;

    // Update head position based on direction
    switch(_head.direction) {
        case DIRECTION_UP:    _head.position.x--; break;
        case DIRECTION_DOWN:  _head.position.x++; break;
        case DIRECTION_LEFT:  _head.position.y--; break;
        case DIRECTION_RIGHT: _head.position.y++; break;
    }

    // Update body segments if snake has body
    if(_size > 1) {
        SnakeSegment* current = _head.next;
        _head.next = new SnakeSegment();
        _head.next->icon = oldIcon;
        _head.next->position = oldPosition;
        _head.next->next = current;
        
        // Remove tail if exceeding max size
        if(_size > MAX_SNAKE_LENGTH) {
            removeTailSegment();
        }
    }
}

Testing Observations Initial testing revealed boundary collision issues requiring additional validation logic. The current implementation allows the snake to move through map boundaries, with directional input responsiveness verified across multiple test sequences. Threaded input handling successfully decouples movement timing from user input polling.

Tags: C++ Linux Snake Game termios pthreads

Posted on Tue, 01 Sep 2026 16:31:28 +0000 by examancer