assignmnet2主要是多线程编写一个青蛙过河的小游戏
语言:C++
环境:
就目前所见做法主要分为两类:将木板移动和青蛙移动分为两部分。第二种是将河的每一条都进行划分,这里我主要采取第二种。(感觉查重率会很低,而且这个方法有自己的问题,我也没搞懂)
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <curses.h>
#include <termios.h>
#include <fcntl.h>
#define ROW 10
#define COLUMN 50
pthread_mutex_t mutex;
pthread_mutex_t mutex2;
struct Node{
int x , y;
Node( int _x , int _y ) : x( _x ) , y( _y ) {};
Node(){} ;
} frog ;
char map[ROW+10][COLUMN] ;
int state = 0; // 0: the game is in progress, 1: win, 2: lose, 3: quit
// Determine a keyboard is hit or not. If yes, return 1. If not, return 0.
int kbhit(void){
struct termios oldt, newt;
int ch;
int oldf;
tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);
ch = getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
fcntl(STDIN_FILENO, F_SETFL, oldf);
if(ch != EOF)
{
ungetc(ch, stdin);
return 1;
}
return 0;
}
void *frog_move( void *threadid){
pthread_mutex_lock(&mutex2);
char optation = getchar();
if (frog.x == ROW ){
map[frog.x][frog.y] = '|';
}
else if (frog.x != ROW){
map[frog.x][frog.y] = '=';
}
if (optation == 'w' || optation == 'W'){
frog.x -= 1;
}
else if (optation == 's' || optation == 'S'){
frog.x += 1;
}
else if (optation == 'a' || optation == 'A'){
frog.y -= 1;
}
else if (optation == 'd' || optation == 'D'){
frog.y += 1;
}
else if (optation == 'q' || optation == 'Q'){
state = 3;
}
pthread_mutex_unlock(&mutex2);
pthread_exit(NULL);
}
int water_speed(int x){
if (x == 1 || x == 3 || x == 5 || x == 7 || x == 9){ //青蛙在木板上的固有流速
return -1;
}
else if (x == 2 || x == 4 || x == 6 || x == 8){
return 1;
}
}
void *logs_move( void *t ){
long riv;
riv = (long) t+1;
/* Move the logs */
int loghead = rand()% (COLUMN-10)+10;
int length = 15;
pthread_mutex_lock(&mutex);
while (state == 0){
int condition = 0;
usleep(70000);
/* Check keyboard hits, to change frog's position or quit the game. */
if (kbhit()){
pthread_t threads_frog;
int rc;
rc = pthread_create(&threads_frog,NULL,frog_move, NULL);
if (rc){
printf("ERROR: return code from pthread_create() is %d", rc);
exit(1);
}
}
for (int i = 1;i<=50;i++){ //每次刷新都是先铺好空格,然后再将空格改为 =
map[riv][(i+COLUMN)%(COLUMN-1)]=' ';
}
if (frog.x==riv){
frog.y += water_speed(riv);
}
if (riv == 1 || riv == 3 || riv == 5 || riv == 7 || riv == 9){ // left
for (int j=15+loghead;j>=loghead;j--){
if (frog.x==riv && (frog.y+1)==(j+50)%49){
condition=1;
}
map[riv][(j+50)%(49)]='=';
}
if (frog.y+1==(loghead+50)%(49)){
condition=0;
}
loghead=(loghead+49)%(50);
}
else if (riv == 2 || riv == 4 || riv == 6 || riv == 8){ // right
for (int j=loghead;j<=length+loghead;j++){
if (frog.x==riv && (frog.y-1)==j%(49)){
condition=1;
}
map[riv][j%(49)]='=';
}
if (frog.y==(length+loghead+50)%49){
condition=0;
}
loghead=(loghead+1)%(49);
}
map[frog.x][frog.y] = '0';
/* Check game's status */
if (frog.x > ROW || frog.y < 1 || frog.y > 48 || (!condition && frog.x==riv)){
state = 2;
}
if (frog.x == 0){
state = 1;
}
/* Print the map on the screen */
if (riv == 1){
printf("\033[H\033[2J");
for(int i = 0; i <= ROW; i++){
puts(map[i]);
}
if (state==1){
pthread_exit(NULL);
}
else if (state==2){
pthread_exit(NULL);
}
else if (state==3){
pthread_exit(NULL);
}
}
pthread_mutex_unlock(&mutex);
}
pthread_exit(NULL);
}
int main( int argc, char *argv[] ){
// Initialize the river map and frog's starting position
memset( map , 0, sizeof( map ) ) ;
int i , j ;
for( i = 1; i < ROW; ++i ){
for( j = 0; j < COLUMN - 1; ++j )
map[i][j] = ' ' ;
}
for( j = 0; j < COLUMN - 1; ++j ){
map[ROW][j] = map[0][j] = '|' ;
}
for( j = 0; j < COLUMN - 1; ++j )
map[0][j] = map[0][j] = '|' ;
frog = Node( ROW, (COLUMN-1) / 2 ) ;
map[frog.x][frog.y] = '0' ;
//Print the map into screen
printf("\033[H\033[2J");
for( i = 0; i <= ROW; ++i)
puts( map[i] );
/* Create pthreads for wood move and frog control. */
pthread_t threads[ROW-1];
int rc;
pthread_mutex_init(&mutex, NULL);
pthread_mutex_init(&mutex2, NULL);
for (long k=0;k<ROW-1;k++){
rc = pthread_create(&threads[k],NULL,logs_move, (void*)k);
if (rc){
printf("ERROR: return code from pthread_create() is %d", rc);
exit(1);
}
}
pthread_join(threads[0],NULL);
/* Display the output for user: win, lose or quit. */
if (state==1){
printf("\033[H\033[2JYou win the game!!\n");
}
else if (state==2){
printf("\033[H\033[2JYou lose the game!!\n");
}
else if (state==3){
printf("\033[H\033[2JYou exit the game.\n");
}
pthread_mutex_destroy(&mutex);
pthread_mutex_destroy(&mutex2);
pthread_exit(NULL);
return 0;
}
借鉴了部分前人的想法,但是在结构上面优化了不少。(主要不变的部分是青蛙在木板上的判定之类的)
写的时候遇到的主要问题是如果有多线程输出的话输出结果会一直闪,所以在这里用 if (riv == 1)来只输出一次即可。
还有一个问题是输出的时候有时没法结束程序,有的时候可以,有的时候也会报错,具体原因尚未深究。