C-Kurs/Pong/Musterlösung: Unterschied zwischen den Versionen
(Die Seite wurde neu angelegt: „== Musterlösung == <pre> #include <curses.h> →dimensions of the field: #define WIDTH 40 #define HEIGHT 15 #define PADDLE_HEIGHT 3 /* positions of playing t...“) |
PaulG (Diskussion | Beiträge) K (verschob „Ckurs/Pong/Musterlösung“ nach „C-Kurs/Pong/Musterlösung“) |
||
(3 dazwischenliegende Versionen von 2 Benutzern werden nicht angezeigt) | |||
Zeile 1: | Zeile 1: | ||
== Musterlösung == | == Musterlösung == | ||
<pre> | <pre> | ||
+ | #include <stdlib.h> | ||
#include <curses.h> | #include <curses.h> | ||
Zeile 8: | Zeile 9: | ||
#define PADDLE_HEIGHT 3 | #define PADDLE_HEIGHT 3 | ||
− | /* positions of | + | /* positions of play things */ |
int pos_p1_y; | int pos_p1_y; | ||
int pos_p2_y; | int pos_p2_y; | ||
Zeile 21: | Zeile 22: | ||
void init() { | void init() { | ||
− | initscr(); / | + | initscr(); /* init for curses */ |
− | noecho(); / | + | noecho(); /* don't display typed chars */ |
− | cbreak(); / | + | cbreak(); /* don't buffer terminal lines */ |
− | keypad(stdscr, TRUE); / | + | keypad(stdscr, TRUE); /* for special keys (e.g. arrow keys) */ |
− | + | nodelay(stdscr, TRUE); /* don't block in getch() */ | |
} | } | ||
Zeile 44: | Zeile 45: | ||
int x,y; | int x,y; | ||
− | / | + | /* print score */ |
printw(" %i %i\n", score_p1, score_p2); | printw(" %i %i\n", score_p1, score_p2); | ||
− | / | + | /* print upper frame */ |
printw("+"); | printw("+"); | ||
for(x=0; x<WIDTH; x++) { | for(x=0; x<WIDTH; x++) { | ||
Zeile 55: | Zeile 56: | ||
for (y=0; y<HEIGHT; y++) { | for (y=0; y<HEIGHT; y++) { | ||
− | / | + | /* first column (x==0) is for player1's paddle */ |
if (y >= pos_p1_y && y < pos_p1_y+PADDLE_HEIGHT) { | if (y >= pos_p1_y && y < pos_p1_y+PADDLE_HEIGHT) { | ||
printw("|#"); | printw("|#"); | ||
Zeile 64: | Zeile 65: | ||
} | } | ||
− | / | + | /* middle columns (0 < x < WIDTH-1) anywhere the ball can be */ |
for (x=1; x<WIDTH-1; x++) { | for (x=1; x<WIDTH-1; x++) { | ||
if (y == pos_ball_y && x == pos_ball_x) { | if (y == pos_ball_y && x == pos_ball_x) { | ||
Zeile 73: | Zeile 74: | ||
} | } | ||
− | / | + | /* last column (x==WIDTH-1) is for player2's paddle */ |
if (y >= pos_p2_y && y < pos_p2_y+PADDLE_HEIGHT) { | if (y >= pos_p2_y && y < pos_p2_y+PADDLE_HEIGHT) { | ||
printw("#|\n"); | printw("#|\n"); | ||
Zeile 83: | Zeile 84: | ||
} | } | ||
− | / | + | /* print lower frame */ |
printw("+"); | printw("+"); | ||
for(x=0; x<WIDTH; x++) { | for(x=0; x<WIDTH; x++) { | ||
Zeile 115: | Zeile 116: | ||
void detect_collision() { | void detect_collision() { | ||
− | / | + | /* ball collides with upper/lower bounds */ |
if (pos_ball_y <= 0 || pos_ball_y >= HEIGHT-1) { | if (pos_ball_y <= 0 || pos_ball_y >= HEIGHT-1) { | ||
dir_ball_y *= -1; | dir_ball_y *= -1; | ||
} | } | ||
− | / | + | /* ball collides with player1's paddle */ |
if (pos_ball_x == 1 && pos_ball_y >= pos_p1_y && pos_ball_y < pos_p1_y + PADDLE_HEIGHT) { | if (pos_ball_x == 1 && pos_ball_y >= pos_p1_y && pos_ball_y < pos_p1_y + PADDLE_HEIGHT) { | ||
dir_ball_x *= -1; | dir_ball_x *= -1; | ||
} | } | ||
− | / | + | /* ball collides with player2's paddle */ |
if (pos_ball_x == WIDTH-2 && pos_ball_y >= pos_p2_y && pos_ball_y < pos_p2_y + PADDLE_HEIGHT) { | if (pos_ball_x == WIDTH-2 && pos_ball_y >= pos_p2_y && pos_ball_y < pos_p2_y + PADDLE_HEIGHT) { | ||
dir_ball_x *= -1; | dir_ball_x *= -1; | ||
Zeile 137: | Zeile 138: | ||
int detect_ball_out() { | int detect_ball_out() { | ||
− | / | + | /* ball is out on left side -> point for player2 */ |
if (pos_ball_x <= 0) { | if (pos_ball_x <= 0) { | ||
return 2; | return 2; | ||
} | } | ||
− | / | + | /* ball is out on right side -> point for player1 */ |
if (pos_ball_x >= WIDTH-1) { | if (pos_ball_x >= WIDTH-1) { | ||
return 1; | return 1; | ||
Zeile 152: | Zeile 153: | ||
int play_round() { | int play_round() { | ||
int ball_out; | int ball_out; | ||
+ | int count = 0; | ||
while( !(ball_out = detect_ball_out()) ) { | while( !(ball_out = detect_ball_out()) ) { | ||
key_processing(); | key_processing(); | ||
− | + | if(count == 0) { | |
− | + | move_ball(); | |
+ | detect_collision(); | ||
+ | } | ||
print_field(); | print_field(); | ||
+ | count = (count + 1) % 5; | ||
+ | usleep(20000); | ||
} | } | ||
return ball_out; | return ball_out; | ||
Zeile 176: | Zeile 182: | ||
} | } | ||
sleep(1); | sleep(1); | ||
+ | flushinp(); /* keys could've been pressed during sleep -> emty the input buffer */ | ||
} | } | ||
− | if (score_p1 | + | if (score_p1 > score_p2) { |
printw("Player 1 wins!\n"); | printw("Player 1 wins!\n"); | ||
} else { | } else { | ||
Zeile 187: | Zeile 194: | ||
endwin(); | endwin(); | ||
+ | } | ||
+ | </pre> | ||
+ | |||
+ | == Musterlösung KI == | ||
+ | Einen halbwegs ausgeglichenen Gegner bringt die folgende Lösung. Die Funktion <tt>ai_opponent</tt> muss dazu in der Schleife von <tt>play_round</tt> am besten nach <tt>key_processing</tt> aufgerufen werden. | ||
+ | <pre> | ||
+ | int can_move() { | ||
+ | if (dir_ball_x < 0) { /* we don't want to move when the ball departs from us */ | ||
+ | return 0; | ||
+ | } | ||
+ | int rnd = rand(); | ||
+ | if (pos_ball_x <= WIDTH / 4) { | ||
+ | rnd &= 0x1f; /* zero with probability 1/32 */ | ||
+ | } else if (pos_ball_x <= WIDTH / 2) { | ||
+ | rnd &= 0x0f; /* zero with probability 1/16 */ | ||
+ | } else if (pos_ball_x <= WIDTH * 3 / 4) { | ||
+ | rnd &= 0x07; /* zero with probability 1/8 */ | ||
+ | } else { | ||
+ | rnd &= 0x03; /* zero with probability 1/4 */ | ||
+ | } | ||
+ | return !rnd; | ||
+ | } | ||
+ | |||
+ | void ai_opponent() { | ||
+ | if (can_move()) { | ||
+ | int middle_pad_pos = pos_p2_y + 1; | ||
+ | if (pos_ball_y < middle_pad_pos) { | ||
+ | if (pos_p2_y > 0) { | ||
+ | pos_p2_y--; | ||
+ | } | ||
+ | } else if (pos_ball_y > middle_pad_pos) { | ||
+ | if (pos_p2_y < HEIGHT - PADDLE_HEIGHT) { | ||
+ | pos_p2_y++; | ||
+ | } | ||
+ | } | ||
+ | } | ||
} | } | ||
</pre> | </pre> | ||
Zeile 192: | Zeile 235: | ||
== Kommentare == | == Kommentare == | ||
Wenn du Anmerkungen zur Aufgabe hast oder Lob und Kritik loswerden möchtest, ist hier die richtige Stelle dafür. Klicke einfach ganz rechts auf "bearbeiten" und schreibe deinen Kommentar direkt ins Wiki. Keine Scheu, es geht nichts kaputt ;) | Wenn du Anmerkungen zur Aufgabe hast oder Lob und Kritik loswerden möchtest, ist hier die richtige Stelle dafür. Klicke einfach ganz rechts auf "bearbeiten" und schreibe deinen Kommentar direkt ins Wiki. Keine Scheu, es geht nichts kaputt ;) | ||
− | |||
− | |||
− | |||
− | |||
− |
Aktuelle Version vom 5. März 2013, 17:37 Uhr
Musterlösung
#include <stdlib.h> #include <curses.h> /* dimensions of the field */ #define WIDTH 40 #define HEIGHT 15 #define PADDLE_HEIGHT 3 /* positions of play things */ int pos_p1_y; int pos_p2_y; int pos_ball_x; int pos_ball_y; int dir_ball_x; int dir_ball_y; /* scores */ int score_p1 = 0; int score_p2 = 0; void init() { initscr(); /* init for curses */ noecho(); /* don't display typed chars */ cbreak(); /* don't buffer terminal lines */ keypad(stdscr, TRUE); /* for special keys (e.g. arrow keys) */ nodelay(stdscr, TRUE); /* don't block in getch() */ } void place_paddles() { pos_p1_y = HEIGHT / 2 - PADDLE_HEIGHT / 2; pos_p2_y = HEIGHT / 2 - PADDLE_HEIGHT / 2; } void place_ball(int dir_x) { pos_ball_x = WIDTH / 2; pos_ball_y = HEIGHT / 2; dir_ball_x = dir_x; dir_ball_y = 1; } void print_field() { clear(); int x,y; /* print score */ printw(" %i %i\n", score_p1, score_p2); /* print upper frame */ printw("+"); for(x=0; x<WIDTH; x++) { printw("-"); } printw("+\n"); for (y=0; y<HEIGHT; y++) { /* first column (x==0) is for player1's paddle */ if (y >= pos_p1_y && y < pos_p1_y+PADDLE_HEIGHT) { printw("|#"); } else if (pos_ball_x == 0 && pos_ball_y == y) { printw("|*"); } else { printw("| "); } /* middle columns (0 < x < WIDTH-1) anywhere the ball can be */ for (x=1; x<WIDTH-1; x++) { if (y == pos_ball_y && x == pos_ball_x) { printw("*"); } else { printw(" "); } } /* last column (x==WIDTH-1) is for player2's paddle */ if (y >= pos_p2_y && y < pos_p2_y+PADDLE_HEIGHT) { printw("#|\n"); } else if (pos_ball_x == WIDTH-1 && pos_ball_y == y) { printw("*|\n"); } else { printw(" |\n"); } } /* print lower frame */ printw("+"); for(x=0; x<WIDTH; x++) { printw("-"); } printw("+\n"); refresh(); } void key_processing() { int ch = getch(); if (ch == KEY_UP) { if (pos_p1_y > 0) { pos_p1_y--; } } else if (ch == KEY_DOWN) { if (pos_p1_y < HEIGHT-PADDLE_HEIGHT) { pos_p1_y++; } } else if (ch == 'w') { if (pos_p2_y > 0) { pos_p2_y--; } } else if (ch == 's') { if (pos_p2_y < HEIGHT-PADDLE_HEIGHT) { pos_p2_y++; } } } void detect_collision() { /* ball collides with upper/lower bounds */ if (pos_ball_y <= 0 || pos_ball_y >= HEIGHT-1) { dir_ball_y *= -1; } /* ball collides with player1's paddle */ if (pos_ball_x == 1 && pos_ball_y >= pos_p1_y && pos_ball_y < pos_p1_y + PADDLE_HEIGHT) { dir_ball_x *= -1; } /* ball collides with player2's paddle */ if (pos_ball_x == WIDTH-2 && pos_ball_y >= pos_p2_y && pos_ball_y < pos_p2_y + PADDLE_HEIGHT) { dir_ball_x *= -1; } } void move_ball() { pos_ball_x += dir_ball_x; pos_ball_y += dir_ball_y; } int detect_ball_out() { /* ball is out on left side -> point for player2 */ if (pos_ball_x <= 0) { return 2; } /* ball is out on right side -> point for player1 */ if (pos_ball_x >= WIDTH-1) { return 1; } return 0; } int play_round() { int ball_out; int count = 0; while( !(ball_out = detect_ball_out()) ) { key_processing(); if(count == 0) { move_ball(); detect_collision(); } print_field(); count = (count + 1) % 5; usleep(20000); } return ball_out; } int main() { init(); place_paddles(); place_ball(1); while(score_p1 < 10 && score_p2 < 10) { int round_won = play_round(); if (round_won == 1) { score_p1++; place_ball(1); } else if (round_won == 2) { score_p2++; place_ball(-1); } sleep(1); flushinp(); /* keys could've been pressed during sleep -> emty the input buffer */ } if (score_p1 > score_p2) { printw("Player 1 wins!\n"); } else { printw("Player 2 wins!\n"); } refresh(); sleep(3); endwin(); }
Musterlösung KI
Einen halbwegs ausgeglichenen Gegner bringt die folgende Lösung. Die Funktion ai_opponent muss dazu in der Schleife von play_round am besten nach key_processing aufgerufen werden.
int can_move() { if (dir_ball_x < 0) { /* we don't want to move when the ball departs from us */ return 0; } int rnd = rand(); if (pos_ball_x <= WIDTH / 4) { rnd &= 0x1f; /* zero with probability 1/32 */ } else if (pos_ball_x <= WIDTH / 2) { rnd &= 0x0f; /* zero with probability 1/16 */ } else if (pos_ball_x <= WIDTH * 3 / 4) { rnd &= 0x07; /* zero with probability 1/8 */ } else { rnd &= 0x03; /* zero with probability 1/4 */ } return !rnd; } void ai_opponent() { if (can_move()) { int middle_pad_pos = pos_p2_y + 1; if (pos_ball_y < middle_pad_pos) { if (pos_p2_y > 0) { pos_p2_y--; } } else if (pos_ball_y > middle_pad_pos) { if (pos_p2_y < HEIGHT - PADDLE_HEIGHT) { pos_p2_y++; } } } }
Kommentare
Wenn du Anmerkungen zur Aufgabe hast oder Lob und Kritik loswerden möchtest, ist hier die richtige Stelle dafür. Klicke einfach ganz rechts auf "bearbeiten" und schreibe deinen Kommentar direkt ins Wiki. Keine Scheu, es geht nichts kaputt ;)