⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 snake.c

📁 linux 用ncurse写的贪食蛇 其中食物会在一段时间内变成障碍物
💻 C
字号:
 /* 贪食蛇 Snake by kikistar.com@gmail.com version 0.4.1 #20060420 * * 以下注释,k&r 表示 The C Programming Language. ISBN 7-302-02412-X/TP.1214 *           algo 表示 严蔚敏、吴伟民编著的<数据结构> ISBN 7-900643-22-2 * * Press '2' to run faster and press '1' to run slower when playing the game. * The faster it runs the more scores you can get. */#include <curses.h>#include <stdlib.h>#include <string.h>#include <time.h>#include <unistd.h>#define INIT_LEN 18	// the length of the snake is INIT_LEN+2 when init.#define FOODS 3		// how many foods display at a time#define BORDER_COLOR	1	// color pairs#define SCORE_COLOR	2#define HEAD_COLOR	3#define BODY_COLOR	4#define FOOD_COLOR	5#define DEVIL_COLOR	6enum GO {NONE, LF, UP, DN, RT};struct snake {  int x;  int y;  enum GO go;  char shape[3];  struct snake *prev;  struct snake *next;};struct FOOD {  int x;  int y;  bool shown;  bool devil;  int age;		// how old is the food. The food turns to devil when  struct FOOD *next;	// it getting too old ( >= food2devil)};void die(int score);void rebirth(struct snake *head);int showlife(int life, int addlife);int myrand(int m, double n);struct snake *init_snake(int y, int x, struct snake **tailp);struct snake *add_node(struct snake *tail);struct FOOD *add_food(struct FOOD *, int row, int col);void show_food(struct snake *, struct FOOD *root, struct FOOD *food,	       int row, int col);struct snake *move_snake(struct snake *head, struct snake *tail);int main(){  struct FOOD *food;  struct FOOD *foodp;  struct snake *head;  struct snake *sp;  struct snake *tail;  int ch, lastch, i, lastcolor, bodycolor;  int x, y, row, col;  int score, step, speed;  int changecolor, food2devil, life;  initscr();  cbreak();  keypad(stdscr, TRUE);  noecho();  curs_set(0);  start_color();  init_pair(BORDER_COLOR, COLOR_WHITE, COLOR_BLUE);  init_pair(SCORE_COLOR, COLOR_BLACK, COLOR_WHITE);  init_pair(HEAD_COLOR, COLOR_CYAN, COLOR_BLACK);  init_pair(BODY_COLOR, COLOR_GREEN, COLOR_BLACK);  init_pair(FOOD_COLOR, COLOR_YELLOW, COLOR_BLACK);  init_pair(DEVIL_COLOR, COLOR_RED, COLOR_BLACK);  init_pair(7, COLOR_RED, COLOR_YELLOW);  init_pair(8, COLOR_YELLOW, COLOR_RED);  init_pair(9, COLOR_BLUE, COLOR_RED);  srand((unsigned) time(0));  /* init snake */  getmaxyx(stdscr, row, col);  y = 1;  x = 2;  if ((head = init_snake(y, x, &tail)) == NULL)      die(-1);  for (i = 1; i <= INIT_LEN; ++i)    if ((tail = add_node(tail)) == NULL)      die(-1);  /* init food */    if ((food = (struct FOOD *) malloc(sizeof(*food))) == NULL)      die(-1);    food->shown = FALSE;    food->age = 0;    food->devil = FALSE;    food->next = NULL;    for (i = 1; i < FOODS; i++)      food = add_food(food, row, col);  /* show border, snake */  attron(COLOR_PAIR(BORDER_COLOR));  box(stdscr, 0, 0);  mvprintw(row - 1, 1,	   " Press \"2\" to run faster, \"1\" to run slower, SPACE to pause ");  attroff(COLOR_PAIR(BORDER_COLOR));  life = 3;  attron(COLOR_PAIR(SCORE_COLOR));  mvprintw(0, 16, " LIFE: %d ", life-1);  attroff(COLOR_PAIR(SCORE_COLOR));  attron(COLOR_PAIR(BODY_COLOR));  mvaddstr(head->y, head->x, head->shape);  attroff(COLOR_PAIR(BODY_COLOR));  /* game starts */  score = 0;  changecolor = 1000;  step = 1;  speed = 500;  lastch = ERR;  bodycolor = COLOR_GREEN;  lastcolor = bodycolor;  while (life > 0){    timeout(speed);    flushinp();    ch = getch();    if (lastch != ERR && lastch == ch)		// when double press      napms(speed);    else      lastch = ch;    switch (ch) {    case KEY_LEFT:      if (head->go == UP || head->go == DN)	head->go = LF;      break;    case KEY_UP:      if (head->go == LF || head->go == RT)	head->go = UP;      break;    case KEY_DOWN:      if (head->go == LF || head->go == RT)	head->go = DN;      break;    case KEY_RIGHT:      if (head->go == UP || head->go == DN)	head->go = RT;      break;    case '2':      attron(COLOR_PAIR(SCORE_COLOR));      if ((speed = speed - 50) >= 50)	mvprintw(0, col - 17, " SPEED %3d km/h ", 550 - speed);      else	speed = speed + 50;      attroff(COLOR_PAIR(SCORE_COLOR));      break;    case '1':      attron(COLOR_PAIR(SCORE_COLOR));      if ((speed = speed + 50) <= 500)	mvprintw(0, col - 17, " SPEED %3d km/h ", 550 - speed);      else	speed = speed - 50;      attroff(COLOR_PAIR(SCORE_COLOR));      break;    case ' ':      if (score >= step)	score = score - step;      attron(COLOR_PAIR(SCORE_COLOR));      mvprintw(0, 1, " SCORE %d ", score);      attroff(COLOR_PAIR(SCORE_COLOR));      timeout(-1);      getch();      continue;      break;    case ERR:      break;    default:	napms(speed);      break;    }    /* food or devil */    food2devil = row + col;    for (foodp = food; foodp != NULL; foodp = foodp->next) {      show_food(head, food, foodp, row, col);      if (foodp->devil == TRUE)	/* do nothing */;      else if (foodp->shown == TRUE	       && foodp->age >= food2devil-20 && foodp->age < food2devil) {	attron(A_BLINK);	mvaddch(foodp->y, foodp->x, '$');	attroff(A_BLINK);	foodp->age++;      }      else if (foodp->shown == TRUE && foodp->age >= food2devil) {	foodp->devil = TRUE;	attron(COLOR_PAIR(DEVIL_COLOR));	mvaddch(foodp->y, foodp->x, 'x');	attroff(COLOR_PAIR(DEVIL_COLOR));	food = add_food(food, row, col);      }      else	foodp->age++;    }    /* move snake */    if ((tail = move_snake(head, tail)) == NULL)      die(-1);    /* die or grow */    if (head->x == 0) {		// hit the wall      mvaddch(head->y, head->x, ' ');      head->x = col-2;      life = showlife(life, -1);    }    else if (head->y == 0) {      mvaddch(head->y, head->x, ' ');      head->y = row-2;      life = showlife(life, -1);    }    else if (head->x == col-1) {      mvaddch(head->y, head->x, ' ');      head->x = 1;      life = showlife(life, -1);    }    else if (head->y == row-1) {      mvaddch(head->y, head->x, ' ');      head->y = 1;      life = showlife(life, -1);    }    else			// hit the snake itself      for (sp = head->next; sp != NULL; sp = sp->next) //k&r section 6.6 p145	if (head->x == sp->x && head->y == sp->y) {	  life = showlife(life, -1);	  if (life == 0)	    die(score);	  else	    rebirth(head);	  break;	}        for (foodp = food; foodp != NULL; foodp = foodp->next)      if (head->x == foodp->x && head->y == foodp->y) {	if (foodp->devil == TRUE) {	// hit the devil	  life = showlife(life, -1);	  attron(COLOR_PAIR(DEVIL_COLOR));	  mvaddch(foodp->y, foodp->x, 'x');	  attroff(COLOR_PAIR(DEVIL_COLOR));	  if (life == 0)	    die(score);	  else	    rebirth(head);	  break;	}	else {				// hit the food	  foodp->shown = FALSE;	  	  step = 51 - (speed / 10);	  score = score + step; 	  beep();	  	  if (score > changecolor) {	    while ((bodycolor=myrand(1, 6)) == lastcolor)	      /* do nothing */;	    init_pair(BODY_COLOR, bodycolor, COLOR_BLACK);	    lastcolor = bodycolor;	    changecolor = changecolor + 1000;	    life = showlife(life, 1);	  }	  attron(COLOR_PAIR(SCORE_COLOR));	  mvprintw(0, 1, " SCORE %d ", score);	  attroff(COLOR_PAIR(SCORE_COLOR));	  	  tail = add_node(tail);	}      }  }  die(score);}int myrand(int m, double n) // rand from m to n. k&r section 7.8.7. man rand.{	// it's not a good function because I don't know how to use rand()  return m + (unsigned) (n*rand()/(RAND_MAX+1.0));}struct snake *init_snake(int y, int x, struct snake **tailp){  struct snake *head;  head = (struct snake *) malloc(sizeof(*head));  *tailp = (struct snake *) malloc(sizeof(**tailp));  if (head == NULL || *tailp == NULL)    return NULL;    head->x = x;  head->y = y;  head->go = RT;  strcpy(head->shape, "@");  head->prev = NULL;  (*tailp)->x = head->x-1;  (*tailp)->y = head->y;  (*tailp)->go = NONE;  strcpy((*tailp)->shape, "#");  (*tailp)->prev = head;  (*tailp)->next = NULL;  head->next = *tailp;  return head;}void die(int score){  beep();  attron(COLOR_PAIR(BORDER_COLOR));  mvprintw(LINES/2-3, (COLS-25)/2, "      GAME OVER !!!     ");  mvprintw(LINES/2-2, (COLS-25)/2, "                        ");  mvprintw(LINES/2-1, (COLS-25)/2, "  Press SPACE to exit.  ");  mvprintw(LINES-2, 1, "http://my.opera.com/419/");  mvprintw(LINES-2, COLS-23, "kikistar.com@gmail.com");  attroff(COLOR_PAIR(BORDER_COLOR));  while (getch() != ' ')    /* do nothing */;  endwin();  if (score >= 0) {    printf("snake: Your score was %d\n", score);    exit(0);  }  else {    printf("snake: Not enough memory!\n");    exit(1);  }}void rebirth(struct snake *head){  napms(500);  struct snake *sp;  head->go = RT;  head->y = 1;  head->x = 2;  for (sp = head->next; sp != NULL; sp = sp->next) {    napms(10);    mvaddch(sp->y, sp->x, ' ');    refresh();    sp->y = 1;    sp->x = 1;  }}int showlife(int life, int addlife){  beep();  int i = life + addlife;  if (i >= 1) {    attron(COLOR_PAIR(SCORE_COLOR));    mvprintw(0, 16, " LIFE: %d ", i-1);    attroff(COLOR_PAIR(SCORE_COLOR));  }  return i;}struct snake *add_node(struct snake *tail) {  struct snake *sp;  sp = (struct snake *) malloc(sizeof(*sp));  if (sp == NULL)    return NULL;    sp->x = tail->x;    sp->y = tail->y;  sp->go = tail->go;  //  sp->shape[0] = tail->shape[0];sp->shape[1]='\0';  strcpy(sp->shape, tail->shape);  sp->next = tail->next;	// tailp->next always be NULL  tail->next = sp;    sp->prev = tail;  tail = sp;  return tail;}struct FOOD *add_food(struct FOOD *food, int row, int col){  struct FOOD *newfood;  if ((newfood = (struct FOOD *) malloc(sizeof(*newfood))) == NULL)    die(-1);  newfood->shown = FALSE;  newfood->age = 0;  newfood->devil = FALSE;  newfood->next = food->next;  food->next = newfood;  return food;}void show_food(struct snake *head,	       struct FOOD *foodroot, struct FOOD *food, int row, int col){  if (food->shown == TRUE)    return;  else {    struct snake *sp;    struct FOOD *foodp;    struct FOOD *foodq;    food->y = myrand(1, row-2);    food->x = myrand(1, col-2);    /* the loop below will not work when foodq = foodroot */    if (foodroot->shown == FALSE)      foodq = foodroot->next;    else      foodq = food;    /* avoid the wall (I don't trust myrand) */    if (food->y < 2 || food->y > row-2 || food->x < 1 || food->x > col-2)      return;    /* avoid the other food */    for (foodp = foodq; foodp != NULL; foodp = foodp->next)      if (food->x == foodp->x && food->y == foodp->y)	if (food != foodp)	  return;    /* avoid the snake */    for (sp = head; sp != NULL; sp = sp->next)      if (food->x == sp->x && food->y == sp->y)	return;    food->age = 0;    food->shown = TRUE;    attron(COLOR_PAIR(FOOD_COLOR));    mvaddch(food->y, food->x, '$');    attroff(COLOR_PAIR(FOOD_COLOR));    refresh();  }}/* 1.擦掉蛇尾 2.蛇尾移到蛇头位置 3.移动蛇头  4.更改相关指针 */struct snake *move_snake(struct snake *head, struct snake *tail){  if (head == NULL || tail == NULL)    return NULL;  mvaddstr(tail->y, tail->x, " ");		// 1.  tail->y = head->y;				// 2.  tail->x = head->x;  attron(COLOR_PAIR(BODY_COLOR));  mvaddstr(tail->y, tail->x, tail->shape);  attroff(COLOR_PAIR(BODY_COLOR));  switch (head->go) {				// 3.  case LF:    head->x--;    break;  case UP:    head->y--;    break;  case DN:    head->y++;    break;  case RT:    head->x++;    break;  }  attron(COLOR_PAIR(HEAD_COLOR));  mvaddstr(head->y, head->x, head->shape);  attroff(COLOR_PAIR(HEAD_COLOR));  struct snake *tailprev;	// 4.  struct snake *headnext;  tailprev = tail->prev;	// save tail->prev  headnext = head->next;	// save head->next  head->next = tail;  tail->next = headnext;  headnext->prev = tail;  tail->prev = head;  tailprev->next = NULL;  refresh();  return tailprev;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -