/* $Id: gobang.c,v 2.3 2004/08/23 15:58:11 Starfish Exp $ */ #include "bbs.h" void gobang_freturn_grid(FILE *fp, int x, int y); void gobang_write_header(FILE * fp); void gobang_init_ai(); int gobang_ki(int x, int y, int c); static const char *num_str[19] = { "A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T" }; static const char *num_str2[19] = { "A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T" }; static int gobang_nowx; static int gobang_nowy; static int gobang_count; static int gobang_old_count; static int gobang_boardsize; static int gobang_now_side; static int gobang_board[20][20]; static int gobang_ai_board[20][20]; static char gobang_log_x[361]; static int gobang_log_y[361]; static char gobang_user1[20]; static char gobang_user2[20]; static int gobang_played; static int gobang_who_wins() { int i; int j; int count_0 = 0; for (i = 0 ; i < gobang_boardsize ; i++ ) { for (j = 0 ; j < gobang_boardsize ; j++ ) { if (gobang_board[i][j] != 0) { /* it is occupied */ if ( i < gobang_boardsize -4 ) { if ( gobang_board[i][j] == gobang_board[i+1][j] && gobang_board[i][j] == gobang_board[i+2][j] && gobang_board[i][j] == gobang_board[i+3][j] && gobang_board[i][j] == gobang_board[i+4][j] ) { /* 5 in a column */ return gobang_board[i][j]; } } if ( j < gobang_boardsize-4 ) { if ( gobang_board[i][j] == gobang_board[i][j+1] && gobang_board[i][j] == gobang_board[i][j+2] && gobang_board[i][j] == gobang_board[i][j+3] && gobang_board[i][j] == gobang_board[i][j+4] ) { /* 5 in a row */ return gobang_board[i][j]; } } if ( (i < gobang_boardsize -4) && (j < gobang_boardsize-4) ) { if ( gobang_board[i][j] == gobang_board[i+1][j+1] && gobang_board[i][j] == gobang_board[i+2][j+2] && gobang_board[i][j] == gobang_board[i+3][j+3] && gobang_board[i][j] == gobang_board[i+4][j+4] ) { /* 5 in a diagonal */ return gobang_board[i][j]; } } if ( (i >= 4) && (j < gobang_boardsize-4) ) { if ( gobang_board[i][j] == gobang_board[i-1][j+1] && gobang_board[i][j] == gobang_board[i-2][j+2] && gobang_board[i][j] == gobang_board[i-3][j+3] && gobang_board[i][j] == gobang_board[i-4][j+4] ) { /* 5 in a diagonal */ return gobang_board[i][j]; } } } else { count_0++; } } } if (count_0==0) { return -1; } return 0; } static void gobang_indigestion(int i) { fprintf(stderr, "嚴重內傷 %d\n", i); } static int gobang_write_file(char *fpath, int *islocal) { /* struct tm *ptime; */ FILE *fp = NULL; /* char ans[TTLEN], *msg; */ int aborted = 0; /* , line = 0, checksum[3], sum = 0, po = y1; */ int i; int i2; int j; int k; int log; int go_start; /* getdata(1, 0, msg, ans, 2, LCECHO); */ if (!*fpath) { sethomepath(fpath, cuser->userid); strcpy(fpath, tempnam(fpath, "ve_")); } if ((fp = fopen(fpath, "w")) == NULL) { gobang_indigestion(5); abort_bbs(0); } gobang_write_header(fp); fprintf(fp, " "); for (i=0; i<19; i++) { if (igobang_boardsize - 10) { fprintf(fp, " "); } fprintf(fp, "%d", gobang_boardsize - i); } else { fprintf(fp, " "); } for (j=0; j<20; j++) { gobang_freturn_grid(fp, j, i); } } if (i==1) { if (gobang_now_side == 1) { fprintf(fp, " →"); } else { fprintf(fp, " "); } if (strcmp(gobang_user1, "???")==0) { fprintf(fp, "黑○:INSERT-COIN "); } else { fprintf(fp, "黑○:%s ", gobang_user1); } } if (i==2) { if (gobang_now_side == 2) { fprintf(fp, " →"); } else { fprintf(fp, " "); } if (strcmp(gobang_user2, "???")==0) { fprintf(fp, "白●:INSERT-COIN "); } else { fprintf(fp, "白●:%s ", gobang_user2); } } if (i==4) { if (gobang_now_side == 1) { fprintf(fp, " 黑"); } else { fprintf(fp, " 白"); } fprintf(fp, "方下子,現為第 %d 著", gobang_count); } if (i==6) { fprintf(fp, " ○ ● ○ ● ○ ● ○ ●"); } if (i==7) { go_start = 0; if (gobang_count > 80) { go_start = (gobang_count / 8 * 8) - 72; fprintf(fp, " -(最頂為第 %d 著)---------------", go_start); } else { fprintf(fp, " --------------------------------"); } } if (i==18) { fprintf(fp, " --------------------------------"); } if ((i>7) && (i<18)) { i2 = i - 8; go_start = 0; if (gobang_count > 80) { go_start = (gobang_count / 8 * 8) - 72; } fprintf(fp, " "); for (k=0; k<8; k++) { log = i2*8+k + go_start; if (log < gobang_count) { fprintf(fp, "%c%d", gobang_log_x[log], gobang_boardsize-gobang_log_y[log]); if (gobang_log_y[log]>gobang_boardsize - 10) { fprintf(fp, " "); } fprintf(fp, " "); } } } fprintf(fp, "\n"); } fclose(fp); return aborted; } void gobang_write_header(FILE * fp) { int result = 0; char *ptr; struct { char author[IDLEN + 1]; char board[IDLEN + 1]; char title[66]; time_t date; /* last post's date */ int number; /* post number */ } postlog; fprintf(fp, "%s %s (%s)\n", str_author1, cuser->userid, cuser->username); memset(&postlog, 0, sizeof(postlog)); strlcpy(postlog.author, cuser->userid, sizeof(postlog.author)); strlcpy(postlog.board, currboard, sizeof(postlog.board)); if (gobang_count > 1 && gobang_old_count != 0) { result = gobang_who_wins(); if ( result==1 ) { snprintf(save_title, sizeof(save_title), "Re: [五子] %s 勝 %s", gobang_user1, gobang_user2); } else if ( result==2 ) { snprintf(save_title, sizeof(save_title), "Re: [五子] %s 負 %s", gobang_user1, gobang_user2); } else if ( result==-1 ) { snprintf(save_title, sizeof(save_title), "Re: [五子] %s 和 %s", gobang_user1, gobang_user2); } else { snprintf(save_title, sizeof(save_title), "Re: [五子] %s 對 %s", gobang_user1, gobang_user2); } } else { snprintf(save_title, sizeof(save_title), "[五子] %s 對 %s", gobang_user1, gobang_user2); } ptr = save_title; strncpy(postlog.title, ptr, 65); postlog.date = now; postlog.number = 1; append_record(".post", (fileheader_t *) & postlog, sizeof(postlog)); save_title[72] = '\0'; fprintf(fp, "標題: %s\n時間: %s\n", save_title, ctime(&now)); } void gobang_freturn_grid(FILE *fp, int x, int y) { char k[3] = "┼"; char k2[3] = ""; int placed = 0; strcpy(k, "┼"); if (x==0) { strcpy(k, "├"); } if (x==gobang_boardsize-1) { strcpy(k, "┤"); } if (y==0) { strcpy(k, "┬"); } if (y==gobang_boardsize-1) { strcpy(k, "┴"); } if ((x==0) && (y==0)) { strcpy(k, "┌"); } if ((x==gobang_boardsize-1) && (y==0)) { strcpy(k, "┐"); } if ((x==gobang_boardsize-1) && (y==gobang_boardsize-1)) { strcpy(k, "┘"); } if ((x==0) && (y==gobang_boardsize-1)) { strcpy(k, "└"); } if (x == gobang_boardsize) { if (y < gobang_boardsize) { if (y > gobang_boardsize - 10) { strcpy(k, " "); } else { strcpy(k, ""); } sprintf(k2, "%d", gobang_boardsize - y); strcat(k, k2); } else { strcpy(k, " "); } } if ((x > gobang_boardsize) || (y >= gobang_boardsize)) { strcpy(k, " "); } if (x < gobang_boardsize) { if (y < gobang_boardsize) { placed = 0; if (gobang_count > 0) { if (num_str[x][0] == gobang_log_x[gobang_count - 1]) { if (y == gobang_log_y[gobang_count - 1]) { if (gobang_board[x][y] == 1) { fprintf(fp, "◇"); } if (gobang_board[x][y] == 2) { fprintf(fp, "◆"); } placed = 1; } } } if (placed == 0) { if (gobang_board[x][y] == 1) { fprintf(fp, "○"); } if (gobang_board[x][y] == 2) { fprintf(fp, "●"); } } } } if (gobang_board[x][y] == 0) { fprintf(fp, "%s", k); } return; } void gobang_return_grid(int x, int y) { char k[3] = "┼"; char k2[3]; strcpy(k, "┼"); if (x==0) { strcpy(k, "├"); } if (x==gobang_boardsize-1) { strcpy(k, "┤"); } if (y==0) { strcpy(k, "┬"); } if (y==gobang_boardsize-1) { strcpy(k, "┴"); } if ((x==0) && (y==0)) { strcpy(k, "┌"); } if ((x==gobang_boardsize-1) && (y==0)) { strcpy(k, "┐"); } if ((x==gobang_boardsize-1) && (y==gobang_boardsize-1)) { strcpy(k, "┘"); } if ((x==0) && (y==gobang_boardsize-1)) { strcpy(k, "└"); } if (x == gobang_boardsize) { if (y < gobang_boardsize) { if (y > gobang_boardsize - 10) { strcpy(k, " "); } else { strcpy(k, ""); } sprintf(k2, "%d", gobang_boardsize - y); strcat(k, k2); } else { strcpy(k, " "); } } if ((x > gobang_boardsize) || (y >= gobang_boardsize)) { strcpy(k, " "); } if (x < gobang_boardsize) { if (y < gobang_boardsize) { if ((gobang_board[x][y] > 0) && (gobang_board[x][y] < 3)) { prints("\033[1;37m"); if (gobang_count > 0) { if (num_str[x][0] == gobang_log_x[gobang_count - 1]) { if (y == gobang_log_y[gobang_count - 1]) { prints("\033[1;33m"); } } } if (gobang_board[x][y] == 1) { prints("○"); } if (gobang_board[x][y] == 2) { prints("●"); } } } } if (gobang_board[x][y] == 0) { prints("\033[0m"); prints(k); } return; } static void import_gobang() { FILE *inf; char buf[256]; char pi[10]; int i; int j; int k; int k2; int cline = 0; int go_start; int dpoint = 0; pi[2] = '\0'; if ((inf = fopen(quote_file, "r"))) { /* char *ptr; */ while (fgets(buf, 256, inf) && buf[0] != '\n'); while (fgets(buf, 256, inf)) { if (cline > 0) { if (cline == 1) { pi[0] = buf[0]; pi[1] = buf[1]; pi[2] = '\0'; gobang_boardsize = atoi(pi); } if (cline < 20) { for (i = 0; i<19; i++) { pi[0] = buf[2 + i*2]; pi[1] = buf[3 + i*2]; pi[2] = '\0'; trim(pi); gobang_board[i][cline-1] = 0; /* use else instead of if only */ if (strcmp(pi, "○")==0) { gobang_board[i][cline-1] = 1; } else if (strcmp(pi, "●")==0) { gobang_board[i][cline-1] = 2; } else if (strcmp(pi, "◇")==0) { gobang_board[i][cline-1] = 1; } else if (strcmp(pi, "◆")==0) { gobang_board[i][cline-1] = 2; } } } if ((cline == 2) || (cline == 3)) { for ( dpoint=52 ; !((buf[dpoint]==' ') || (buf[dpoint]=='\0')); dpoint++); for (j=0; j 8) && (cline < 19)) { go_start = 0; if (gobang_count > 80) { go_start = (gobang_count / 8 * 8) - 72; } for (k=0; k<8; k++) { k2 = (cline - 9) * 8 + k + go_start; if (k2 < gobang_count) { gobang_log_x[k2] = buf[44 + k*4]; if (buf[46 + k*4] == ' ') { pi[0] = buf[45 + k*4]; pi[1] = '\0'; } else { pi[0] = buf[45 + k*4]; pi[1] = buf[46 + k*4]; pi[2] = '\0'; } gobang_log_y[k2] = gobang_boardsize - atoi(pi); } } } } cline++; } } } void gobang_new_board() { int i; int j; for (i=0; i<19; i++) { for (j=0; j<19; j++) { gobang_board[i][j] = 0; } } } void gobang_movecur() { move(gobang_nowy + 3, gobang_nowx*2 + 4); } void gobang_drawline(int line) { int i = 0; int i2, log, k; int go_start; move(line, 0); clrtoeol(); prints(" "); if (line == 0) { if (gobang_played > 1) { prints("注意: 你在這次編輯中下子多過一著"); } else { prints("\033[33;44m 討論區五子棋 ver 1.25 by phchui (bbs.hkday.net) \033[0m"); } } if (line == 2) { prints(" "); for (i=0; i<19; i++) { if (i < gobang_boardsize) { prints("%s", num_str2[i]); } else { prints(" "); } } prints(" "); } if ((line >= 3) && (line <=21)) { if (line - 3 < gobang_boardsize) { if (line > gobang_boardsize - 7) { prints(" "); } prints("%d", 3 + gobang_boardsize - line); } else { prints(" "); } for (i=0; i<20; i++) { gobang_return_grid(i, line-3); } prints("\033[0m"); } if (line == 4) { prints(" "); if (gobang_now_side == 1) { prints("→"); } else { prints(" "); } if (strcmp(gobang_user1, "???")==0) { prints("黑○:INSERT-COIN "); } else { prints("黑○:%s ", gobang_user1); } } if (line == 5) { prints(" "); if (gobang_now_side == 2) { prints("→"); } else { prints(" "); } if (strcmp(gobang_user2, "???")==0) { prints("白●:INSERT-COIN "); } else { prints("白●:%s ", gobang_user2); } } if (line == 7) { prints("第 %d 著", gobang_count+1); } if (line == 8) { if (gobang_now_side == 1) { prints("輪到黑方下子"); } else { prints("輪到白方下子"); } } if (line==10) { go_start = 0; if (gobang_count > 80) { go_start = (gobang_count / 8 * 8) - 72; prints(" -(最頂為第 %d 著)---------------", go_start); } else { prints(" --------------------------------"); } } if (i==21) { prints(" --------------------------------"); } if ((line>10) && (line<21)) { i2 = line - 11; go_start = 0; if (gobang_count > 80) { go_start = (gobang_count / 8 * 8) - 72; } prints(" "); for (k=0; k<8; k++) { log = i2*8+k + go_start; if (log < gobang_count) { prints("%c%d", gobang_log_x[log], gobang_boardsize-gobang_log_y[log]); if (gobang_log_y[log]>gobang_boardsize - 10) { prints(" "); } prints(" "); } } } if (line == 22) { if (gobang_count == 0) { prints(" 前設佈置: [\033[1;33mM\033[0m] 調整棋盤 "); prints("[\033[1;33mA\033[0m] 放置黑子 "); prints("[\033[1;33mB\033[0m] 放置白子 "); prints("[\033[1;33mC\033[0m] 重設棋盤 "); } } if (line == 23) { prints(" 按 [\033[1;32m2846\033[0m] 方向控制 [" "\033[1;32mSPACE\033[0m] "); if (gobang_played > 0) { prints("決定下子 "); } else { prints("下子並開始遊戲 "); } if (gobang_played > 0) { prints("[\033[1;32mS\033[0m] 儲存並退出 "); } prints("[\033[1;32mQ\033[0m] 取消並退出"); } return; } int kill_gobang(int x, int y, int c) { int count = 0; if (c==3) { c = gobang_board[x][y]; } if (c==0) { return 0; } if (gobang_ai_board[x][y] != 0) { return 0; } gobang_ai_board[x][y] = 1; gobang_board[x][y] = 0; if (x>0) { if (gobang_board[x-1][y] == c) { count = count + kill_gobang(x-1, y, c); } } if (x0) { if (gobang_board[x][y-1] == c) { count = count + kill_gobang(x, y-1, c); } } if (y= gobang_boardsize) { return 0; } if (y >= gobang_boardsize) { return 0; } if (gobang_ai_board[x][y] != 0) { return 0; } gobang_ai_board[x][y] = 1; if (gobang_board[x][y] == 0) { return 1; } if (gobang_board[x][y] == c) { ki_pt = ki_pt + gobang_ki(x-1, y, c); ki_pt = ki_pt + gobang_ki(x+1, y, c); ki_pt = ki_pt + gobang_ki(x, y-1, c); ki_pt = ki_pt + gobang_ki(x, y+1, c); } return ki_pt; } void gobang_init_ai() { int i; int j; for (i=0; i<20; i++) { for (j=0; j<20; j++) { gobang_ai_board[i][j] = 0; } } } void put_gobang(int side) { int original; // int ki_pt; if (gobang_board[gobang_nowx][gobang_nowy] != 0) { return; } original = gobang_board[gobang_nowx][gobang_nowy]; gobang_board[gobang_nowx][gobang_nowy] = side; if (gobang_nowx >= 0) { if (gobang_board[gobang_nowx-1][gobang_nowy] != side) { if (gobang_firstki(gobang_nowx-1, gobang_nowy, 3) == 0) { gobang_init_ai(); /* kill_gobang(gobang_nowx-1,gobang_nowy,3); */ } } if (gobang_nowx < gobang_boardsize-1) { if (gobang_board[gobang_nowx+1][gobang_nowy] !=side) { if (gobang_firstki(gobang_nowx+1, gobang_nowy, 3) == 0) { gobang_init_ai(); /* kill_gobang(gobang_nowx+1,gobang_nowy,3); */ } } } if (gobang_nowy > 0) { if (gobang_board[gobang_nowx][gobang_nowy-1] !=side) { if (gobang_firstki(gobang_nowx, gobang_nowy-1, 3) == 0) { gobang_init_ai(); /* kill_gobang(gobang_nowx,gobang_nowy-1,3); */ } } } if (gobang_nowy < gobang_boardsize-1) { if (gobang_board[gobang_nowx][gobang_nowy+1] !=side) { if (gobang_firstki(gobang_nowx, gobang_nowy+1, 3) == 0) { gobang_init_ai(); /* kill_gobang(gobang_nowx,gobang_nowy+1,3); */ } } } gobang_init_ai(); /* ki_pt = gobang_firstki(gobang_nowx, gobang_nowy, side); if (ki_pt==0) { gobang_board[gobang_nowx][gobang_nowy] = original; return; } */ gobang_log_x[gobang_count] = num_str[gobang_nowx][0]; gobang_log_y[gobang_count] = gobang_nowy; gobang_count++; gobang_played++; if (side == 1) { strcpy(gobang_user1, currutmp->userid); } if (side == 2) { strcpy(gobang_user2, currutmp->userid); } if (side == 1) { gobang_now_side = 2; } else { gobang_now_side = 1; } } } static void display_gobang() { int i; /* int j; */ for (i=0; i<24; i++) { gobang_drawline(i); /* 19┌┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┐19 18├┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┤18 → 黑○:UserA 17├┼○┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┤17 白●:UserB 16├┼┼+┼┼┼┼┼+┼┼┼┼┼+┼┼┤16 15├┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┤15 第 5 著 14├┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┤14 輪到黑方下子 13├┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┤13 12├┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┤12 11├┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┤11 黑方得子:0 10├┼┼+┼┼┼┼┼+┼┼┼┼┼+┼┼┤10 白方得子:0 9├┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┤ 9 8├┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┤ 8 7├┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┤ 7 黑方pass 0 次 6├┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┤ 6 白方pass 0 次 5├┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┤ 5 4├┼┼+┼┼┼┼┼+┼┼┼┼┼+┼┼┤ 4 3├┼┼●┼┼┼┼┼┼┼┼┼┼┼┼◆┼┤ 3 計點法:空地減死子 2├┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┤ 2 黑讓 0 子,貼 3.5 目 1└┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┘ 1 ABCDEFGHJKLMNOPQRST*/ } } static void display_gobang_win(int who_win) { if (who_win == 1) { prints(" 黑○:%s 已經贏了", gobang_user1); } else if (who_win == 2) { prints(" 白●:%s 已經贏了", gobang_user2); } else if (who_win == -1) { prints(" 打成平手, 請開新局"); } } /* 主程式、鍵盤處理 */ int vedit_gobang(char *fpath, int saveheader, int *islocal) { int ch; int exit_flag = 0; int result = 0; gobang_boardsize = 15; gobang_nowx = 0; gobang_nowy = 0; gobang_now_side = 1; gobang_count = 0; gobang_old_count = 0; gobang_played = 0; gobang_new_board(); strcpy(gobang_user1, "???"); strcpy(gobang_user2, "???"); if (*quote_file) { import_gobang(); } result = gobang_who_wins(); clear(); if (result == 0) { display_gobang(); } else { exit_flag = 1; display_gobang_win(result); } while (exit_flag == 0) { gobang_movecur(); oflush(); ch = igetkey(); switch (ch) { case 'M' : case 'm' : if (gobang_count ==0) { gobang_boardsize = gobang_boardsize + 2; if (gobang_boardsize > 19) { gobang_boardsize = 9; } display_gobang(); } break; case KEY_UP : case '8' : gobang_nowy--; if (gobang_nowy < 0) { gobang_nowy = gobang_boardsize-1; } break; case KEY_DOWN : case '2' : gobang_nowy++; if (gobang_nowy >= gobang_boardsize) { gobang_nowy = 0; } break; case KEY_LEFT : case '4' : gobang_nowx--; if (gobang_nowx < 0) { gobang_nowx = gobang_boardsize-1; } break; case KEY_RIGHT : case '6' : gobang_nowx++; if (gobang_nowx >= gobang_boardsize) { gobang_nowx = 0; } break; case ' ' : /** if (gobang_played > 0) { break; } */ put_gobang(gobang_now_side); display_gobang(); break; case 'A': case 'a': if (gobang_count > 0) { break; } if (gobang_board[gobang_nowx][gobang_nowy] == 1) { gobang_board[gobang_nowx][gobang_nowy] = 0; } else { gobang_board[gobang_nowx][gobang_nowy] = 1; } gobang_drawline(gobang_nowy + 3); break; case 'B': case 'b': if (gobang_count > 0) { break; } if (gobang_board[gobang_nowx][gobang_nowy] == 2) { gobang_board[gobang_nowx][gobang_nowy] = 0; } else { gobang_board[gobang_nowx][gobang_nowy] = 2; } gobang_drawline(gobang_nowy + 3); break; case 'C': case 'c': if (gobang_count > 0) { break; } gobang_new_board(); display_gobang(); break; case 'S': case 's': if (gobang_played > 0) { gobang_write_file(fpath, NULL); result = gobang_who_wins(); if (result != 0) { clear(); display_gobang_win(result); } return 0; } else { move(0,0); clrtoeol(); prints("你未下棋不能儲存"); } break; case 'Q': case 'q': exit_flag = 1; return -1; break; } } return -1; }