Commit bedf0794 by aostap

Ussimängu kood

parent 05d21e0c
Showing with 677 additions and 0 deletions
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <ncurses.h>
#include <time.h>
#define ROWS 20
#define COLS 45
#define MENU_ROWS 25
#define START_LENGTH 1
#define MAX_LENGTH 900
#define MAX_SPAWNS 900
#define STRUCT_LEN 64
#define MAX_SCORES 1000
#define GAME_WIN_SCORE 900000
#define SCORE_OUTPUT_MAX 3
#define FOOD_CHAR 'O'
#define STOP 0
#define UP 1
#define DOWN 2
#define LEFT 3
#define RIGHT 4
typedef struct {
int x, y;
} position;
int fieldX, fieldY;
int fX, fY;
WINDOW *field;
void Colors();
void MenuWindow();
void SnakeGame();
void SnakeStartingPosition(int *x, int *y, position *snake);
void SpawnApple(int *fx, int *fy, position *apple, position *snake, int length);
void GrowSnake(position *snake, int n);
void ReadScores(int max, int a, WINDOW *score, int center);
void PrintScore(int score);
void ScoreWindow();
void LiveScoreWindow(int score);
void PrintLiveScore(int score);
void PlaceBackBlocks(position *snake, int n);
void MoveSnakeHead(int x, int y, position *snake);
bool CheckSelfCollision(position *snake, int length);
bool CheckBorderCollision(position *snake);
void RemoveSnakeTail(position *snake, int n);
void UpdateSnake_Apple(position *apple, position *snake, int n);
_Bool EmptyCoordinates(int *fx, int *fy, position *snake, int n);
bool gameover = false;
void Setup()
{
// initialize ncurses
initscr();
// enable colors
start_color();
Colors();
// disable line buffering, allow each keystroke to be processed immediately
cbreak();
// don't echo user input to the screen
noecho();
srand(time(NULL));
// remove cursor
curs_set(0);
}
void Colors()
{
init_pair(1, COLOR_GREEN, COLOR_GREEN); // snake color
init_pair(2, COLOR_RED, COLOR_RED); // apple color
init_pair(3, COLOR_GREEN, COLOR_BLACK); // green ascii snake
init_pair(4, COLOR_RED, COLOR_BLACK); // red borders
init_pair(5, COLOR_WHITE, COLOR_BLACK); // white text
init_pair(6, COLOR_WHITE, COLOR_WHITE); // gray borders
}
void Menu()
{
MenuWindow();
// counter for default
int count = 0;
while (count <= 0)
{
int input = getch();
switch (input) {
case 's':
SnakeGame();
count++;
break;
case 'h':
ScoreWindow();
count++;
break;
case 'q':
count++;
break;
default:
break;
}
}
}
void MenuWindow()
{
clear();
refresh();
int xMax, yMax;
getmaxyx(stdscr, yMax, xMax);
WINDOW *menu = newwin(yMax/2, xMax/2, yMax/4, xMax/4);
box(menu, 0, 0);
int center = xMax / 4;
wattron(menu, COLOR_PAIR(5));
mvwprintw(menu, 1, center - 10, "WELCOME TO SNAKE GAME!");
mvwprintw(menu, 3, center - 12, "PRESS 's' TO PLAY SNAKE GAME");
mvwprintw(menu, 4, center - 12, "PRESS 'h' TO VIEW HIGH SCORES");
mvwprintw(menu, 5, center - 12, "PRESS 'q' TO QUIT");
wattroff(menu, COLOR_PAIR(5));
wattron(menu, COLOR_PAIR(3));
mvwprintw(menu, 5, center - MENU_ROWS, " Y");
mvwprintw(menu, 6, center - MENU_ROWS, " .-^-.");
mvwprintw(menu, 7, center - MENU_ROWS, " / \\ .- ~ ~ -.");
mvwprintw(menu, 8, center - MENU_ROWS, "() () / _ _ `. _ _ _");
mvwprintw(menu, 9, center - MENU_ROWS, " \\_ _/ / / \\ \\ . ~ _ _ ~ .");
mvwprintw(menu, 10, center - MENU_ROWS, " | | / / \\ \\ .' .~ ~-. `.");
mvwprintw(menu, 11, center - MENU_ROWS, " | | / / ) ) / / `.`.");
mvwprintw(menu, 12, center - MENU_ROWS, " \\ \\_ _/ / / / / / `'");
mvwprintw(menu, 13, center - MENU_ROWS, " \\_ _ _.' / / ( (");
mvwprintw(menu, 14, center - MENU_ROWS, " / / \\ \\");
mvwprintw(menu, 15, center - MENU_ROWS, " / / \\ \\");
mvwprintw(menu, 16, center - MENU_ROWS, " / / ) )");
mvwprintw(menu, 17, center - MENU_ROWS, " ( ( / /");
mvwprintw(menu, 18, center - MENU_ROWS, " `. `. .' /");
mvwprintw(menu, 19, center - MENU_ROWS, " `. ~ - - - - ~ .'");
mvwprintw(menu, 20, center - MENU_ROWS, " ~ . _ _ _ _ . ~");
wattroff(menu, COLOR_PAIR(3)); // end green snake
wattron(menu, COLOR_PAIR(4)); // red borders
wborder(menu, '|', '|', '-', '-', '+', '+', '+', '+');
wattroff(menu, COLOR_PAIR(4)); // end red borders
wrefresh(menu);
}
void ScoreWindow(WINDOW *score, int center)
{
clear();
refresh();
int xMax, yMax;
getmaxyx(stdscr, yMax, xMax);
score = newwin(yMax/2, xMax/2, yMax/4, xMax/4);
box(score, 0, 0);
center = xMax / 4;
mvwprintw(score, 5, center - 7, "HIGH SCORE!!!");
ReadScores(MAX_SCORES, 0, score, center);
mvwprintw(score, 8, center - 8, "LAST THREE SCORES:");
ReadScores(MAX_SCORES, 1, score, center);
mvwprintw(score, 15, center - 10, "PRESS 'b' TO GO BACK");
wattron(score, COLOR_PAIR(4)); // red borders
wborder(score, '|', '|', '-', '-', '+', '+', '+', '+');
wattroff(score, COLOR_PAIR(4)); // end red borders
wrefresh(score);
// counter for default
int count = 0;
while (count <= 0)
{
int input = getch();
switch (input) {
case 'b':
Menu();
count++;
break;
default:
refresh();
break;
}
}
}
void Gamefield() {
clear();
refresh();
int xMax, yMax;
getmaxyx(stdscr, yMax, xMax);
fieldY = (yMax/2) - (ROWS/2);
fieldX = (xMax/2) - (COLS/2);
fX = (yMax/2) + (ROWS/2);
fY = (xMax/2) + (COLS/2);
field = newwin(ROWS, COLS, fieldY, fieldX);
box(field, 0, 0);
nodelay(field, TRUE);
wattron(field, COLOR_PAIR(6)); // white borders
wborder(field, '|', '|', '-', '-', '+', '+', '+', '+');
wattroff(field, COLOR_PAIR(6)); // end white borders
wrefresh(field);
}
void LiveScoreWindow(int score)
{
clear();
refresh();
int xMax, yMax;
getmaxyx(stdscr, yMax, xMax);
WINDOW *scoreWindow = newwin(yMax/2, xMax/2, yMax/4, xMax/4);
box(scoreWindow, 0, 0);
int center = xMax / 4;
mvwprintw(scoreWindow, 3, center - 6, "SCORE");
mvwprintw(scoreWindow, 3, center, "%d", score);
mvwprintw(scoreWindow, 5, center - 10, "PRESS 'y' TO PLAY AGAIN");
mvwprintw(scoreWindow, 6, center - 10, "PRESS 'n' TO GO TO MENU");
wattron(scoreWindow, COLOR_PAIR(4)); // red borders
wborder(scoreWindow, '|', '|', '-', '-', '+', '+', '+', '+');
wattroff(scoreWindow, COLOR_PAIR(4)); // end red borders
// Refresh windows
refresh();
wrefresh(field);
wrefresh(scoreWindow);
// counter for default
int count = 0;
while (count <= 0)
{
int input = getch();
switch (input) {
case 'y':
gameover = false;
SnakeGame();
count++;
break;
case 'n':
Menu();
count++;
break;
default:
break;
}
}
}
void GameWon()
{
clear();
refresh();
int xMax, yMax;
getmaxyx(stdscr, yMax, xMax);
WINDOW *scoreWindow = newwin(yMax/2, xMax/2, yMax/4, xMax/4);
box(scoreWindow, 0, 0);
int center = xMax / 4;
mvwprintw(scoreWindow, 5, center - 10, "GAME WON!");
mvwprintw(scoreWindow, 7, center - 10, "PRESS 'y' TO PLAY AGAIN");
mvwprintw(scoreWindow, 8, center - 10, "PRESS 'n' TO GO TO MENU");
wattron(scoreWindow, COLOR_PAIR(4)); // red borders
wborder(scoreWindow, '|', '|', '-', '-', '+', '+', '+', '+');
wattroff(scoreWindow, COLOR_PAIR(4)); // end red borders
// Refresh windows
refresh();
wrefresh(field);
wrefresh(scoreWindow);
// counter for default
int count = 0;
while (count <= 0)
{
int input = getch();
switch (input) {
case 'y':
gameover = false;
SnakeGame();
count++;
break;
case 'n':
Menu();
count++;
break;
default:
break;
}
}
}
void SnakeGame()
{
Gamefield();
position snake[MAX_LENGTH];
position apple[MAX_SPAWNS];
gameover = false;
int length;
int direction;
// snake coordinates
int x, y;
// apple coordinates
int fx, fy;
int score = 0;
// Time delay for snake movement
struct timespec sleep_time;
sleep_time.tv_sec = 0;
sleep_time.tv_nsec = 100000000;
length = START_LENGTH;
// Inital direction waits for user input
direction = STOP;
// Snake starting point
SnakeStartingPosition(&x, &y, snake);
// Apple starting point and spawns in apples
SpawnApple(&fx, &fy, apple, snake, length);
while (!gameover) {
// Get user input
int input = wgetch(field);
switch (input) {
case 'a':
if (direction != RIGHT) {
direction = LEFT;
}
break;
case 'd':
if (direction != LEFT) {
direction = RIGHT;
}
break;
case 'w':
if (direction != DOWN) {
direction = UP;
}
break;
case 's':
if (direction != UP) {
direction = DOWN;
}
break;
// Pause game
case 'p':
while (getch() != 'p');
break;
// Exit game
case 'q':
gameover = true;
break;
default:
break;
}
// Input Logic
switch (direction) {
case UP:
y--;
break;
case DOWN:
y++;
break;
case LEFT:
x--;
break;
case RIGHT:
x++;
break;
}
// Check if apple has been eaten
if (x == fx && y == fy)
{
GrowSnake(snake, length);
length++;
score += 100;
SpawnApple(&fx, &fy, apple, snake, length);
} else {
RemoveSnakeTail(snake, length);
}
PlaceBackBlocks(snake, length);
MoveSnakeHead(x, y, snake);
// Game over situations
if (CheckBorderCollision(snake))
{
gameover = true;
LiveScoreWindow(score);
}
if (CheckSelfCollision(snake, length))
{
gameover = true;
LiveScoreWindow(score);
}
PrintLiveScore(score);
UpdateSnake_Apple(apple, snake, length);
refresh();
nanosleep(&sleep_time, NULL);
// Game is won
if (score >= GAME_WIN_SCORE)
{
GameWon();
score = 0;
}
}
PrintScore(score);
}
void SnakeStartingPosition(int *x, int *y, position *snake)
{
*x = rand() % (COLS - 2) + fieldX + 1;
*y = rand() % (ROWS - 2) + fieldY + 1;
snake[0].x = *x;
snake[0].y = *y;
}
void SpawnApple(int *fx, int *fy, position *apple, position *snake, int length)
{
do {
*fx = rand() % (COLS - 2) + fieldX + 1;
*fy = rand() % (ROWS - 2) + fieldY + 1;
apple[0].x = *fx;
apple[0].y = *fy;
} while (!EmptyCoordinates(fx, fy, snake, length));
}
_Bool EmptyCoordinates(int *fx, int *fy, position *snake, int n)
{
// Check if the coordinates are occupied by the snake
for (int i = 0; i < n; i++) {
if (*fx == snake[i].x && *fy == snake[i].y) {
return FALSE;
}
}
return TRUE;
}
void GrowSnake(position *snake, int n)
{
snake[n].x = snake[n - 1].x;
snake[n].y = snake[n - 1].y;
}
void MoveSnakeHead(int x, int y, position *snake)
{
snake[0].x = x;
snake[0].y = y;
}
bool CheckSelfCollision(position *snake, int length) {
for (int i = 1; i < length; i++) {
if (snake[i].x == snake[0].x && snake[i].y == snake[0].y) {
return true;
}
}
return false;
}
bool CheckBorderCollision(position *snake)
{
// left border
if(snake[0].x == fieldX) {
return true;
}
// upper border
if(snake[0].y == fieldY) {
return true;
}
// lower border
if(snake[0].y == fieldY + ROWS - 1){
return true;
}
// right border
if(snake[0].x == fieldX + COLS - 1){
return true;
}
return false;
}
void PlaceBackBlocks(position *snake, int n)
{
int i;
position temp;
for (i = n; i > 0; i--) {
temp = snake[i - 1];
snake[i] = temp;
}
}
void RemoveSnakeTail(position *snake, int n)
{
mvaddch(snake[n - 1].y, snake[n - 1].x, ' ');
snake[n - 1].x = - 1;
snake[n - 1].y = - 1;
}
void UpdateSnake_Apple(position *apple, position *snake, int n)
{
for (int i = 0; i < n; i++)
{
if (snake[i].y != -1 && snake[i].x != -1)
{
attron(COLOR_PAIR(1)); // set snake color
for (int i = 0; i < n; i++)
{
mvaddch(snake[i].y, snake[i].x, ' ' | A_REVERSE);
}
attroff(COLOR_PAIR(1)); // unset snake color
}
}
attron(COLOR_PAIR(2)); // set food color
mvaddch(apple->y, apple->x, FOOD_CHAR);
attroff(COLOR_PAIR(2)); // unset food color
}
void PrintLiveScore(int score)
{
mvprintw(fieldY + ROWS, fieldX , "SCORE");
mvprintw(fieldY + ROWS, fieldX + COLS - 3, "%d", score);
}
void PrintScore(int score)
{
FILE *fp = fopen("scores.txt", "a");
if (fp == NULL)
{
printf("Error opening file!\n");
}
time_t currentTime;
struct tm *currentTimeStruct;
time(&currentTime);
currentTimeStruct = localtime(&currentTime);
char timeString[STRUCT_LEN];
strftime(timeString, STRUCT_LEN, "%Y.%m.%d %H:%M:%S", currentTimeStruct);
fprintf(fp, "%s score: %d\n", timeString, score);
fclose(fp);
}
void ReadScores(int max, int a, WINDOW *score, int center)
{
FILE *fp = fopen("scores.txt", "r");
if (fp == NULL)
{
printf("Error opening file!\n");
}
int last_scores[MAX_SCORES];
int i = 0;
int count = 0;
while (fscanf(fp, "%*s %*s %*s %d", &last_scores[i]) == 1)
{
i++;
count++;
if (i >= max)
{
printf("Error! Count has reached the limit!\n");
break;
}
if (count == 0)
{
printf("No scores have yet been saved\n");
}
}
if (a == 0)
{
int max_score = last_scores[0]; // start with the first score
if (count == 0)
{
mvwprintw(score, 6, center - 10, "No scores have been saved!");
} else {
for (int i = 1; i < count; i++)
{
if (last_scores[i] > max_score)
{
max_score = last_scores[i]; // update the max score if a higher score is found
}
}
mvwprintw(score, 6, center - 10, " %d\n", max_score);
}
} else {
if (count == 0)
{
mvwprintw(score, 10, center - 10, "No scores have been saved!");
} else {
int j = 0;
for (i = count - 1; i > 0 && j < SCORE_OUTPUT_MAX; i--)
{
mvwprintw(score, 10 + j, center - 10, " %d\n", last_scores[i]);
j++;
}
}
}
}
int main()
{
Setup();
//SnakeGame();
Menu();
//getch();
endwin();
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment