Загрузка данных


#include <ncurses.h>
#define HEIGHT 25
#define WEIGHT 80

#define BALL_SYMBOL 'o'
#define PADDLE_SYMBOL '|'
#define BORDER_SYMBOL '-'
#define SPACE_SYMBOL ' '

#define PADDLE_OFFSET (PADDLE_SIZE - 1)
#define PADDLE_SIZE 3

#define PADDLE_LEFT_X 10
#define PADDLE_RIGHT_X (WEIGHT - PADDLE_LEFT_X)
#define PADDLE_START_Y 12

#define BALL_START_X (WEIGHT / 2)
#define BALL_START_Y (HEIGHT / 2)

#define BALL_START_VX 1
#define BALL_START_VY 1

#define PLAYER_LEFT_UP 'A'
#define PLAYER_LEFT_DOWN 'Z'
#define PLAYER_RIGHT_UP 'K'
#define PLAYER_RIGHT_DOWN 'M'

#define QUIT_KEY 'q'
#define QUIT_ESC 27
#define TICK_MS 50

#define WIN_SCORE 21

typedef struct {
    int paddle_left_y;
    int paddle_right_y;
    int paddle_left_x;
    int paddle_right_x;
    int player_left_score;
    int player_right_score;
    int vx;
    int vy;
    int ball_x;
    int ball_y;
} GameState;

void DrawField(GameState gs) {
    erase();
    for (int y = 0; y < HEIGHT; y++) {
        for (int x = 0; x < WEIGHT; x++) {
            if (y == 0 || y == HEIGHT - 1) {
                mvaddch(y, x, BORDER_SYMBOL);
            } else if (x == gs.paddle_left_x && (y == gs.paddle_left_y || y == gs.paddle_left_y + 1 ||
                                                 y == gs.paddle_left_y + PADDLE_OFFSET)) {
                mvaddch(y, x, PADDLE_SYMBOL);
            } else if (x == gs.paddle_right_x && (y == gs.paddle_right_y || y == gs.paddle_right_y + 1 ||
                                                  y == gs.paddle_right_y + PADDLE_OFFSET)) {
                mvaddch(y, x, PADDLE_SYMBOL);
            } else if (x == gs.ball_x && y == gs.ball_y) {
                mvaddch(y, x, BALL_SYMBOL);
            } else {
                mvaddch(y, x, SPACE_SYMBOL);
            }
        }
    }
    mvprintw(HEIGHT, 0, "Score: %d : %d   (q to quit)", gs.player_left_score, gs.player_right_score);
    refresh();
}

int MovePaddle(int y, int direction) {
    int new_y = y;
    if (direction < 0 && y > 1) new_y = y - 1;
    if (direction > 0 && y < HEIGHT - 1 - PADDLE_SIZE) new_y = y + 1;
    return new_y;
}

GameState Reset(GameState gs) {
    if (gs.ball_x + gs.vx < gs.paddle_left_x) {
        gs.player_right_score++;
        gs.ball_x = BALL_START_X;
        gs.ball_y = BALL_START_Y;
        gs.paddle_left_y = PADDLE_START_Y;
        gs.paddle_right_y = PADDLE_START_Y;
    }
    if (gs.ball_x + gs.vx > gs.paddle_right_x) {
        gs.player_left_score++;
        gs.ball_x = BALL_START_X;
        gs.ball_y = BALL_START_Y;
        gs.paddle_left_y = PADDLE_START_Y;
        gs.paddle_right_y = PADDLE_START_Y;
    }
    return gs;
}

int CheckPaddleCrash(GameState gs) {
    if ((gs.ball_x + gs.vx == gs.paddle_left_x && gs.ball_y + gs.vy >= gs.paddle_left_y &&
         gs.ball_y + gs.vy <= gs.paddle_left_y + PADDLE_OFFSET) ||
        (gs.ball_x + gs.vx == gs.paddle_right_x && gs.ball_y + gs.vy >= gs.paddle_right_y &&
         gs.ball_y + gs.vy <= gs.paddle_right_y + PADDLE_OFFSET))
        gs.vx = -gs.vx;
    return gs.vx;
}

int CheckBorderCrash(GameState gs) {
    if (gs.ball_y + gs.vy >= HEIGHT - 1 || gs.ball_y + gs.vy <= 0) gs.vy = -gs.vy;
    return gs.vy;
}

int ReadDirection(int ch, int up, int down) {
    int dir = 0;
    if (ch == up) dir = -1;
    if (ch == down) dir = 1;
    return dir;
}

GameState HandleInput(GameState gs, int ch) {
    int dir_left = ReadDirection(ch, PLAYER_LEFT_UP, PLAYER_LEFT_DOWN);
    int dir_right = ReadDirection(ch, PLAYER_RIGHT_UP, PLAYER_RIGHT_DOWN);
    gs.paddle_left_y = MovePaddle(gs.paddle_left_y, dir_left);
    gs.paddle_right_y = MovePaddle(gs.paddle_right_y, dir_right);
    return gs;
}

GameState StepBall(GameState gs) {
    gs.vx = CheckPaddleCrash(gs);
    gs.vy = CheckBorderCrash(gs);
    gs = Reset(gs);
    gs.ball_x = gs.ball_x + gs.vx;
    gs.ball_y = gs.ball_y + gs.vy;
    return gs;
}

int GetWinner(GameState gs) {
    int winner = 0;
    if (gs.player_left_score >= WIN_SCORE) winner = 1;
    if (gs.player_right_score >= WIN_SCORE) winner = 2;
    return winner;
}

void PrintWinner(int winner) {
    if (winner == 1) printf("\nПоздравляем! Победил левый игрок!\n");
    if (winner == 2) printf("\nПоздравляем! Победил правый игрок!\n");
}

int main(void) {
    initscr();
    noecho();
    cbreak();
    keypad(stdscr, TRUE);
    timeout(TICK_MS);
    curs_set(0);

    GameState gs = {.paddle_left_y = PADDLE_START_Y,
                    .paddle_right_y = PADDLE_START_Y,
                    .paddle_left_x = PADDLE_LEFT_X,
                    .paddle_right_x = PADDLE_RIGHT_X,
                    .player_left_score = 0,
                    .player_right_score = 0,
                    .vx = BALL_START_VX,
                    .vy = BALL_START_VY,
                    .ball_x = BALL_START_X,
                    .ball_y = BALL_START_Y};

    int winner = 0;
    int running = 1;
    while (running) {
        int ch = getch();
        if (ch == QUIT_KEY || ch == QUIT_ESC) {
            running = 0;
        } else {
            gs = HandleInput(gs, ch);
            gs = StepBall(gs);
            DrawField(gs);
            winner = GetWinner(gs);
            if (winner != 0) {
                running = 0;
            }
        }
    }

    endwin();
    PrintWinner(winner);
    return 0;
}