[M3] 俄羅斯方塊(單人版) tetris.c

看板Maple (BBS架站)作者時間22年前 (2003/01/02 12:47), 編輯推噓0(000)
留言0則, 0人參與, 最新討論串1/5 (看更多)
::: src/so/tetris.c ::: 說明:程序中的 HAVE_MONEY_ISM 部分是本站用到的錢幣 處理方法,大家可略過或刪除。 -------------以下是程序正文--------------- /* so/tetris.c */ /* 俄羅斯方塊在線游戲 */ /* 原作者: zhch.bbs@bbs.nju.edu.cn */ /* 改寫者: hightman.bbs@bbs.hightman.net */ #include "bbs.h" #ifdef HAVE_TETRIS #define HAVE_RECORD // 把最高條數和得分記錄在 attr lib中 #define MAX_MAP_WIDTH 10 #define MAX_MAP_HEIGHT 20 #define FN_TETRIS_REC "game/tetris.top" #define BLOCK_CHAR "■" static int last_ypos, last_xpos, last_style, last_dir; static int game_times, max_lines, max_scores; #ifdef HAVE_MONEY_ISM static int win_money; #endif static int map[MAX_MAP_HEIGHT + 1][MAX_MAP_WIDTH + 2] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 }; static int style_x[7][4][4] = { 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 1, 1, 1, 1, 0, 1, 2, 3, 1, 1, 1, 1, 0, 1, 1, 2, 1, 0, 1, 0, 0, 1, 1, 2, 1, 0, 1, 0, 1, 2, 0, 1, 0, 0, 1, 1, 1, 2, 0, 1, 0, 0, 1, 1, 0, 1, 2, 0, 0, 1, 1, 1, 2, 0, 1, 2, 0, 0, 0, 1, 0, 1, 2, 2, 1, 1, 0, 1, 0, 0, 1, 2, 0, 1, 0, 0, 0, 1, 2, 1, 1, 0, 1, 1, 1, 0, 1, 2, 0, 0, 1, 0 }; static int style_y[7][4][4] = { 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 2, 3, 1, 1, 1, 1, 0, 1, 2, 3, 0, 0, 1, 1, 0, 1, 1, 2, 0, 0, 1, 1, 0, 1, 1, 2, 0, 0, 1, 1, 0, 1, 1, 2, 0, 0, 1, 1, 0, 1, 1, 2, 0, 0, 0, 1, 0, 0, 1, 2, 0, 1, 1, 1, 0, 1, 2, 2, 0, 0, 0, 1, 0, 1, 2, 2, 0, 1, 1, 1, 0, 0, 1, 2, 0, 0, 0, 1, 0, 1, 1, 2, 0, 1, 1, 1, 0, 1, 1, 2 }; static int my_style, direction, ypos, xpos, number; static int new_style, my_lines, delay, level, start_time, my_scores; typedef struct { char userid[IDLEN + 1]; int lines; int scores; } TOP_LIST; static TOP_LIST top_list[MAX_MAP_HEIGHT]; // --------------------------------------- // // function start // --------------------------------------- // static void move_map(y, x) int y, x; { move(y + 2, 2 * x); } static int top_cmp(a, b) TOP_LIST *a, *b; { int retval; retval = b->scores - a->scores; if (retval == 0) retval = b->lines - a->lines; return retval; } static void top_init() { int fd, i = 0; memset(top_list, 0, sizeof(TOP_LIST) * MAX_MAP_HEIGHT); fd = open(FN_TETRIS_REC, O_RDONLY); if (fd >= 0) { while (read(fd, &top_list[i], sizeof(TOP_LIST)) == sizeof(TOP_LIST)) i++; close(fd); } } static int save_top() { int fd, wflag, i; i = 0; wflag = 1; memset(top_list, 0, sizeof(TOP_LIST) * MAX_MAP_HEIGHT); if ((fd = open(FN_TETRIS_REC, O_RDWR | O_CREAT, 0600)) >= 0) { f_exlock(fd); while (read(fd, &top_list[i], sizeof(TOP_LIST)) == sizeof(TOP_LIST)) { if (!str_cmp(top_list[i].userid, cuser.userid)) { wflag = 0; if (top_list[i].scores < max_scores) { top_list[i].scores = max_scores; wflag = 2; } if (top_list[i].lines < max_lines) { top_list[i].lines = max_lines; wflag = 2; } } i++; } if (wflag == 1) { if (i < MAX_MAP_HEIGHT) { strcpy(top_list[i].userid, cuser.userid); top_list[i].scores = max_scores; top_list[i].lines = max_lines; i++; } else { if (top_list[i-1].scores < max_scores) { strcpy(top_list[i-1].userid, cuser.userid); top_list[i-1].scores = max_scores; top_list[i-1].lines = max_lines; } else wflag = 0; } } if (wflag) { xsort(top_list, i, sizeof(TOP_LIST), top_cmp); lseek(fd, 0, SEEK_SET); wflag = write(fd, top_list, sizeof(TOP_LIST) * i); ftruncate(fd, sizeof(TOP_LIST) * i); } f_unlock(fd); close(fd); } return wflag; } #ifdef HAVE_RECORD static void save_record() { TetrisRecord tr; if (attr_get(cuser.userid, ATTR_TETRIS_REC, &tr) < 0) { tr.exp = 1000; tr.win = tr.total = tr.maxlines = tr.maxscore = 0; } if (max_lines > tr.maxlines) tr.maxlines = max_lines; if (max_scores > tr.maxscore) tr.maxscore = max_scores; attr_put(cuser.userid, ATTR_TETRIS_REC, &tr); } #endif static void show_welcome() { move(2, 0); prints("歡迎光臨 %s!\n\n", cuser.userid); prints("鍵盤設置如下: \n"); prints("左: '\033[1;32ma\033[m', '\033[1;32m←\033[m';\n"); prints("右: '\033[1;32md\033[m', '\033[1;32m→\033[m';\n"); prints("下: '\033[1;32ms\033[m', '\033[1;32m↓\033[m';\n"); prints("順時針轉動: '\033[1;32mk\033[m', <\033[1;32m回車\033[m>;"); prints("逆時針轉動: '\033[1;32mh\033[m', '\033[1;32m↑\033[m'; 180度轉動: '\033 [1;32mj\033[m';\n"); prints("快降: '<空格>', 暫停: <\033[1;32m ^S \033[m>.\n"); prints("退出: '\033[1;32m^C ^D\033[m', '\033[1;32m^D\033[m'.\n\n"); prints("每消 \033[1;33m30\033[m 行升一級, 消1行得1分、行3分、三行7分、四行15分!\n"); prints("退出游戲後方能刷新排行榜!! 進入排行榜者有□金挀喔~~^0^"); vmsg(NULL); } static void tetris_init(lines) int lines; { /* init screen */ game_times++; /* get the rand style and set other parameter */ start_time = time(0); srand(start_time); level = lines; lines = MAX_MAP_HEIGHT - lines; for (ypos = 0; ypos < MAX_MAP_HEIGHT; ypos++) { for (xpos = 1; xpos <= MAX_MAP_WIDTH; xpos++) { if (ypos >= lines) map[ypos][xpos] = rand() % 3; else map[ypos][xpos] = 0; } } new_style = rand() % 7; my_lines = my_scores = 0; delay = 40; do { delay *= 0.9; } while (lines++ < MAX_MAP_HEIGHT); } static void show_map() { int y, x; for (y = 0; y <= MAX_MAP_HEIGHT; y++) { move_map(y, 0); clrtoeol(); for(x = 0; x <= MAX_MAP_WIDTH + 1; x++) { if (map[y][x] == 8) outs("▓"); else if (map[y][x]) outs(BLOCK_CHAR); else outs(" "); } if (y == 0) prints(" \033[1;33;44m == %s 本周俄羅斯方塊高手榜 ==\033[m", str_site); else if(top_list[y-1].userid[0]) prints(" %2d %-14s %6d 分 %6d 條", y, top_list[y-1].userid, top_list[y-1].scores, top_list[y-1].lines); } } /* ypost, xpos, style, direction, flag */ static void show_block(y, x, k, d, f) int y, x, k, d, f; { if (d == -1) return; for (number = 0; number <= 3; number++) { move_map(y + style_y[k][d][number], x + style_x[k][d][number]); if (f) outs(BLOCK_CHAR); else outs(" "); } move(1, 0); } static void move_block() { if (last_ypos == ypos && last_xpos == xpos && last_style == my_style && last_dir == direction) return; show_block(last_ypos, last_xpos, last_style, last_dir, 0); last_ypos = ypos; last_xpos = xpos; last_style = my_style; last_dir = direction; show_block(last_ypos, last_xpos, last_style, last_dir, 1); } /* ypost, xpos, style, direction */ static int crash(x, y, k, d) int x, y, k, d; { for (number = 0; number <= 3; number++) if (map[y + style_y[k][d][number]][x + style_x[k][d][number]]) return 1; return 0; } static void check_lines() { int y, x, s = 1; for (y = 0; y < MAX_MAP_HEIGHT; y++) { for (x = 1; x <= MAX_MAP_WIDTH; x++) { if (map[y][x] == 0) break; } if (x == (MAX_MAP_WIDTH + 1)) { int y2; s *= 2; /* 消去行上部全部下移! */ for (y2 = y; y2 > 0; y2--) { for (x = 1; x <= MAX_MAP_WIDTH; x++) map[y2][x] = map[y2-1][x]; } for (x = 1; x <= MAX_MAP_WIDTH; x++) map[0][x] = 0; if (++my_lines % 30 == 0) { delay *= 0.9; level ++; bell(); } } } s -= 1; if (s > 0) { s = s * (10 + level) / 10; my_scores += s; show_map(); move(b_lines, 0); clrtoeol(); prints("本局成績: 總消去條數: \033[1;32m%d\033[m , 總得分 \033[1;32m%d\033[m, 等級: \033[1;32m%d\033[m", my_lines, my_scores, level); } } static void arrived() { int y, x; for (number = 0; number <= 3; number++) { y = ypos + style_y[my_style][direction][number]; x = xpos + style_x[my_style][direction][number]; map[y][x] = my_style + 1; } check_lines(); last_dir = -1; } int p_tetris() { int ch, clock; clear(); utmp_mode(M_TETRIS); vs_bar("俄羅斯方塊 - 單人版"); show_welcome(); game_times = max_lines = max_scores = 0; #ifdef HAVE_MONEY_ISM win_money = 0; #endif top_init(); start: last_dir = -1; ch = vans("從第幾級別開始玩(0-9)? [0]"); if (ch < '0') ch = 0; else if (ch > '9') ch = 9; else ch = ch - 48; tetris_init(ch); move(1, 0); clrtobot(); refresh(); prints("第 \033[1;32m%d\033[m 局", game_times); show_map(); vmsg("游戲開始!"); move(b_lines, 0); clrtoeol(); prints("本局成績: 總消去條數: \033[1;32m0\033[m, 總得分: \033[1;32m0\033[m , 等級: \033[1;32m%d\033[m", level); add_io(0, 0); while (1) { my_style = new_style; #if 1 if (!str_cmp(cuser.userid, str_sysop)) new_style = rand() % 2; else new_style = rand() % 7; #else new_style = rand() % 7; #endif direction = 0; xpos = 3; ypos = 0; move_map(0, MAX_MAP_WIDTH + 2); outs(" "); move_map(1, MAX_MAP_WIDTH + 2); outs(" "); show_block(0, MAX_MAP_WIDTH + 2, new_style, direction, new_style + 1); move_block(); if (crash(xpos, ypos, my_style, direction)) /* game over */ break; clock = times(0); while(1) { ch = vkey(); switch(ch) { case Ctrl('L') : break; case Ctrl('S') : add_io(0, 60); vmsg("游戲暫停!"); move(b_lines, 0); clrtoeol(); prints("本局成績: 總消去條數: \033[1;32m%d\033[m, 總得分 \033[1;32m% d\033[m, 等級: \033[1;32m%d\033[m", my_lines, my_scores, level); add_io(0, 0); break; case 'A' : case 'a' : case KEY_LEFT : if (!crash(xpos - 1, ypos, my_style, direction)) { xpos --; move_block(); } break; case 'D' : case 'd' : case KEY_RIGHT : if (!crash(xpos + 1, ypos, my_style, direction)) { xpos++; move_block(); } break; case 'H' : case 'h' : case KEY_UP : if (!crash(xpos, ypos, my_style, (direction + 3) % 4)) { direction = (direction + 3) % 4; move_block(); } break; case 'K' : case 'k' : case KEY_ENTER : if (!crash(xpos, ypos, my_style, (direction + 1) % 4)) { direction = (direction + 1) % 4; move_block(); } break; case 'J' : case 'j' : if (!crash(xpos, ypos, my_style, (direction + 2) % 4)) { direction = (direction + 2) % 4; move_block(); } break; case 'S' : case 's' : case 'Z' : case 'z' : case KEY_DOWN : clock = times(0); if (crash(xpos, ypos + 1, my_style, direction)) { arrived(); ch = '#'; } else { ypos++; move_block(); } break; case ' ' : while (!crash(xpos, ypos + 1, my_style, direction)) ypos++; move_block(); arrived(); ch = '#'; break; default : break; } if (ch == Ctrl('C') || ch == Ctrl('D') || ch == '#') break; /* down auto */ if ((times(0) - clock > delay)) { clock = times(0); if (crash(xpos, ypos + 1, my_style, direction)) { arrived(); break; } else { ypos++; move_block(); } } } if (ch == Ctrl('C') || ch == Ctrl('D')) { break; } } add_io(0, 60); if (my_scores > max_scores) max_scores = my_scores; if (my_lines > max_lines) max_lines = my_lines; #ifdef HAVE_MONEY_ISM win_money += my_scores * 20; #endif ch = vans("本局結束!您還要繼續玩嗎? [Y/n]"); if (ch != 'n' & ch != 'N') goto start; #ifdef HAVE_RECORD save_record(); #endif #undef HAVE_RECORD ch = save_top(); if (ch > 0) { #ifdef HAVE_MONEY_ISM win_money <<= 1; #endif vmsg("游戲結束,您刷新了您的記錄!"); } else vmsg("游戲結束,您未能刷新高手榜!"); #ifdef HAVE_MONEY_ISM if (win_money > 1000) { char buf[128]; ACCT acct; sprintf(buf, "恭喜!您獲得□金 %d 元。", win_money); if (acct_load(&acct, cuser.userid) >= 0) { acct.money += win_money; cuser.money = acct.money; acct_save(&acct); } vmsg(buf); } #endif return 0; } #endif /* _HAVE_TETRIS_ */ -- ※ 來源:.溫馨小屋 bbs.feeling.smth.org.[FROM: lib.zju.edu.cn]
文章代碼(AID): #-4yHN00 (Maple)
文章代碼(AID): #-4yHN00 (Maple)