SVN / public / code / vorlesung-05 / Snake.cpp

Revision 3042
Date2026-05-19T16:27:14+02:00
Committercu1017
Download
// Copyright 2024, University of Freiburg
// Chair of Algorithms and Data Structures
// Author: Hannah Bast <bast@cs.uni-freiburg.de>,

#include "./Snake.h"
#include <unistd.h>

// ____________________________________________________________________________
void Snake::play() {
  drawBorder(TerminalManager::Green);
  drawSnake(TerminalManager::Red);
  terminalManager_->refresh();

  // Initial speed in pixels per second.
  double speed = 10;

  // Acceleration in pixel per second squared.
  double acceleration = 2;

  // The absolute distance moved since the last call to moveSnake(). If it
  // becomes > 1 we have to move the snake by one pixel.
  double distance = 0;
  while (true) {
    // Let the game run until the snake has moved by at least one pixel.
    while (true) {
      UserInput userInput = terminalManager_->getUserInput();
      if (userInput.isEscape()) {
        return;
      }
      handleKey(userInput);
      usleep(1000);
      distance += speed / 1000;
      speed += acceleration / 1000;
      if (distance >= 1.0) {
        distance -= 1.0;
        break;
      }
    }

    // Move the snake to the next position (leave a trail of white pixels).
    drawSnake(TerminalManager::White);
    moveSnake();
    drawSnake(TerminalManager::Red);
    terminalManager_->refresh();

    // If the snake collides with the border, quit after three seconds.
    if (collidesWithBorder()) {
      usleep(3'000'000);
      return;
    }
  }
}

// ____________________________________________________________________________
Snake::Snake(TerminalManager *terminalManager)
    : terminalManager_(terminalManager) {
  posRow_ = terminalManager_->numRows() / 2;
  posCol_ = terminalManager_->numCols() / 2;
  dirRow_ = 0;
  dirCol_ = 1;
}

// ____________________________________________________________________________
void Snake::drawBorder(int color) {
  for (int row = 0; row < terminalManager_->numRows(); row++) {
    terminalManager_->drawPixel(row, 0, color);
    terminalManager_->drawPixel(row, terminalManager_->numCols() - 1, color);
  }
  for (int col = 0; col < terminalManager_->numCols(); col++) {
    terminalManager_->drawPixel(0, col, color);
    terminalManager_->drawPixel(terminalManager_->numRows() - 1, col, color);
  }
}

// ____________________________________________________________________________
void Snake::drawSnake(int color) {
  terminalManager_->drawPixel(posRow_, posCol_, color);
}

// ____________________________________________________________________________
bool Snake::collidesWithBorder() {
  return posRow_ <= 0 || posRow_ >= terminalManager_->numRows() - 1 ||
         posCol_ <= 0 || posCol_ >= terminalManager_->numCols() - 1;
}

// ____________________________________________________________________________
void Snake::moveSnake() {
  posRow_ = posRow_ + dirRow_;
  posCol_ = posCol_ + dirCol_;
}

// ____________________________________________________________________________
void Snake::handleKey(UserInput userInput) {
  if (userInput.isKeyDown()) {
    if (dirRow_ != -1) {
      dirRow_ = 1;
      dirCol_ = 0;
    }
  } else if (userInput.isKeyUp()) {
    if (dirRow_ != 1) {
      dirRow_ = -1;
      dirCol_ = 0;
    }
  } else if (userInput.isKeyLeft()) {
    if (dirCol_ != 1) {
      dirRow_ = 0;
      dirCol_ = -1;
    }
  } else if (userInput.isKeyRight()) {
    if (dirCol_ != -1) {
      dirRow_ = 0;
      dirCol_ = 1;
    }
  }
}