Загрузка данных
#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;
}