diff options
Diffstat (limited to 'mbbsd/othello.c')
-rw-r--r-- | mbbsd/othello.c | 568 |
1 files changed, 0 insertions, 568 deletions
diff --git a/mbbsd/othello.c b/mbbsd/othello.c deleted file mode 100644 index 27e385dc..00000000 --- a/mbbsd/othello.c +++ /dev/null @@ -1,568 +0,0 @@ -/* $Id$ */ -#include "bbs.h" - -#define LOGFILE "etc/othello.log" -#define NR_TABLE 2 - -#define true 1 -#define false 0 -#define STARTX 3 -#define STARTY 20 -#define NONE_CHESS " " -#define WHITE_CHESS "●" -#define BLACK_CHESS "○" -#define HINT_CHESS "#" -#define NONE 0 -#define HINT 1 -#define BLACK 2 -#define WHITE 3 - -#define INVERT(COLOR) (((COLOR))==WHITE?BLACK:WHITE) - -struct OthelloData { - char nowx, nowy; - char number[2]; - - char pass; - char if_hint; - int think, which_table; - - char nowboard[10][10]; - char evaltable[NR_TABLE + 1][10][10]; -}; - -static const char *CHESS_TYPE[] = {NONE_CHESS, HINT_CHESS, BLACK_CHESS, WHITE_CHESS}; -static const char DIRX[] = {-1, -1, -1, 0, 1, 1, 1, 0}; -static const char DIRY[] = {-1, 0, 1, 1, 1, 0, -1, -1}; -static const char init_table[NR_TABLE + 1][5][5] = { - {{0, 0, 0, 0, 0}, - {0, 30, -3, 2, 2}, - {0, -3, -3, -1, -1}, - {0, 2, -1, 1, 1}, - {0, 2, -1, 1, 0}}, - - {{0, 0, 0, 0, 0}, - {0, 70, 5, 20, 30}, - {0, 5, -5, 3, 3}, - {0, 20, 3, 5, 5}, - {0, 30, 3, 5, 5}}, - - {{0, 0, 0, 0, 0}, - {0, 5, 2, 2, 2}, - {0, 2, 1, 1, 1}, - {0, 2, 1, 1, 1}, - {0, 2, 1, 1, 1}} -}; - -static void -print_chess(struct OthelloData *od, int x, int y, char chess) -{ - move(STARTX - 1 + x * 2, STARTY - 2 + y * 4); - if (chess != HINT || od->if_hint == 1) - outs(CHESS_TYPE[(int)chess]); - else - outs(CHESS_TYPE[NONE]); - refresh(); -} - -static void -printboard(struct OthelloData *od) -{ - int i; - - move(STARTX, STARTY); - outs("┌─┬─┬─┬─┬─┬─┬─┬─┐"); - for (i = 0; i < 7; i++) { - move(STARTX + 1 + i * 2, STARTY); - outs("│ │ │ │ │ │ │ │ │"); - move(STARTX + 2 + i * 2, STARTY); - outs("├─┼─┼─┼─┼─┼─┼─┼─┤"); - } - move(STARTX + 1 + i * 2, STARTY); - outs("│ │ │ │ │ │ │ │ │"); - move(STARTX + 2 + i * 2, STARTY); - outs("└─┴─┴─┴─┴─┴─┴─┴─┘"); - print_chess(od, 4, 4, WHITE); - print_chess(od, 5, 5, WHITE); - print_chess(od, 4, 5, BLACK); - print_chess(od, 5, 4, BLACK); - move(3, 56); - prints("(黑)%s", cuser.userid); - move(3, 72); - outs(": 02"); - move(4, 56); - outs("(白)電腦 : 02"); - move(6, 56); - outs("# 可以下之處"); - move(7, 56); - outs("[q] 退出"); - move(8, 56); - outs("[h] 開啟/關閉 提示"); - move(9, 56); - outs("[Enter][Space] 下棋"); - move(10, 56); - outs("上:↑, i"); - move(11, 56); - outs("下:↓, k"); - move(12, 56); - outs("左:←, j"); - move(13, 56); - outs("右:→, l"); -} - -static int -get_key(struct OthelloData *od, int x, int y) -{ - int ch; - - move(STARTX - 1 + x * 2, STARTY - 1 + y * 4); - ch = igetch(); - move(STARTX - 1 + x * 2, STARTY - 2 + y * 4); - if (od->nowboard[x][y] != HINT || od->if_hint == 1) - outs(CHESS_TYPE[(int)od->nowboard[x][y]]); - else - outs(CHESS_TYPE[NONE]); - return ch; -} - -static int -eatline(int i, int j, char color, int dir, char chessboard[][10]) -{ - int tmpx, tmpy; - char tmpchess; - - tmpx = i + DIRX[dir]; - tmpy = j + DIRY[dir]; - tmpchess = chessboard[tmpx][tmpy]; - if (tmpchess == -1) - return false; - if (tmpchess != INVERT(color)) - return false; - - tmpx += DIRX[dir]; - tmpy += DIRY[dir]; - tmpchess = chessboard[tmpx][tmpy]; - while (tmpchess != -1) { - if (tmpchess < BLACK) - return false; - if (tmpchess == color) { - while (i != tmpx || j != tmpy) { - chessboard[i][j] = color; - i += DIRX[dir]; - j += DIRY[dir]; - } - return true; - } - tmpx += DIRX[dir]; - tmpy += DIRY[dir]; - tmpchess = chessboard[tmpx][tmpy]; - } - return false; -} - -static int -if_can_put(int x, int y, char color, char chessboard[][10]) -{ - int i, temp, checkx, checky; - - if (chessboard[x][y] < BLACK) - for (i = 0; i < 8; i++) { - checkx = x + DIRX[i]; - checky = y + DIRY[i]; - temp = chessboard[checkx][checky]; - if (temp < BLACK) - continue; - if (temp != color) - while (chessboard[checkx += DIRX[i]][checky += DIRY[i]] > HINT) - if (chessboard[checkx][checky] == color) - return true; - } - return false; -} - -static int -get_hint(struct OthelloData *od, char color) -{ - int i, j, temp = 0; - - for (i = 1; i <= 8; i++) - for (j = 1; j <= 8; j++) { - if (od->nowboard[i][j] == HINT) - od->nowboard[i][j] = NONE; - if (if_can_put(i, j, color, od->nowboard)) { - od->nowboard[i][j] = HINT; - temp++; - } - print_chess(od, i, j, od->nowboard[i][j]); - } - return temp; -} - -static void -eat(int x, int y, int color, char chessboard[][10]) -{ - int k; - - for (k = 0; k < 8; k++) - eatline(x, y, color, k, chessboard); -} - -static void -end_of_game(struct OthelloData *od, int quit) -{ - FILE *fp; - char *opponent[] = {"", "CD-65", "", "嬰兒", "小孩", "", "大人", "專家"}; - - move(STARTX - 1, 30); - outs(" "); - move(22, 35); - fp = fopen(LOGFILE, "a"); - if (quit) { - if (od->number[0] == 2 && od->number[1] == 2) { - if (fp) - fclose(fp); - return; - } - fprintf(fp, "在%s級中, %s臨陣脫逃\n", opponent[od->think], cuser.userid); - if (fp) - fclose(fp); - return; - } - if (od->number[0] > od->number[1]) { - prints("你贏了電腦%02d子", od->number[0] - od->number[1]); - if (od->think == 6 && od->number[0] - od->number[1] >= 50) - demoney(200); - if (od->think == 7 && od->number[0] - od->number[1] >= 40) - demoney(200); - if (fp) - fprintf(fp, "在%s級中, %s以 %02d:%02d 贏了電腦%02d子\n", - opponent[od->think], cuser.userid, od->number[0], od->number[1], - od->number[0] - od->number[1]); - } else if (od->number[1] > od->number[0]) { - prints("電腦贏了你%02d子", od->number[1] - od->number[0]); - if (fp) { - fprintf(fp, "在%s級中, ", opponent[od->think]); - if (od->number[1] - od->number[0] > 20) - fprintf(fp, "電腦以 %02d:%02d 慘電%s %02d子\n", od->number[1], - od->number[0], cuser.userid, od->number[1] - od->number[0]); - else - fprintf(fp, "電腦以 %02d:%02d 贏了%s %02d子\n", od->number[1], - od->number[0], cuser.userid, od->number[1] - od->number[0]); - } - } else { - outs("你和電腦打成平手!!"); - if (fp) - fprintf(fp, "在%s級中, %s和電腦以 %02d:%02d 打成了平手\n", - opponent[od->think], cuser.userid, od->number[1], od->number[0]); - } - if (fp) - fclose(fp); - move(1, 1); - igetch(); -} - -static void -othello_redraw(struct OthelloData *od) -{ - int i, j; - - for (i = 1; i <= 8; i++) - for (j = 1; j <= 8; j++) - print_chess(od, i, j, od->nowboard[i][j]); -} - -static int -player(struct OthelloData *od, char color) -{ - int ch; - - if (get_hint(od, color)) { - while (true) { - ch = get_key(od, od->nowx, od->nowy); - switch (ch) { - case 'J': - case 'j': - case KEY_LEFT: - od->nowy--; - break; - case 'L': - case 'l': - case KEY_RIGHT: - od->nowy++; - break; - case 'I': - case 'i': - case KEY_UP: - od->nowx--; - break; - case 'K': - case 'k': - case KEY_DOWN: - od->nowx++; - break; - case ' ': - case KEY_ENTER: - if (od->nowboard[(int)od->nowx][(int)od->nowy] != HINT) - break; - od->pass = 0; - od->nowboard[(int)od->nowx][(int)od->nowy] = color; - eat(od->nowx, od->nowy, color, od->nowboard); - print_chess(od, od->nowx, od->nowy, color); - return true; - case 'q': - end_of_game(od, 1); - return false; - case 'H': - case 'h': - od->if_hint = od->if_hint ^ 1; - othello_redraw(od); - break; - } - if (od->nowx == 9) - od->nowx = 1; - if (od->nowx == 0) - od->nowx = 8; - if (od->nowy == 9) - od->nowy = 1; - if (od->nowy == 0) - od->nowy = 8; - } - } else { - od->pass++; - if (od->pass == 1) { - move(23, 34); - outs("你必需放棄這一步!!"); - igetch(); - move(28, 23); - outs(" "); - } else { - end_of_game(od,0); - return false; - } - } - return 0; -} - -static void -init(struct OthelloData *od) -{ - int i, j, i1, j1; - - memset(od, 0, sizeof(struct OthelloData)); - od->nowx = 4; - od->nowy = 4; - od->number[0] = od->number[1] = 2; - for (i = 1; i <= 8; i++) - for (j = 1; j <= 8; j++) { - i1 = 4.5 - abs(4.5 - i); - j1 = 4.5 - abs(4.5 - j); - od->evaltable[0][i][j] = init_table[0][i1][j1]; - od->evaltable[1][i][j] = init_table[1][i1][j1]; - } - memset(od->nowboard, NONE, sizeof(od->nowboard)); - for(i=0;i<10;i++) - od->nowboard[i][0]=od->nowboard[0][i]=od->nowboard[i][9]=od->nowboard[9][i]=-1; - od->nowboard[4][4] = od->nowboard[5][5] = WHITE; - od->nowboard[4][5] = od->nowboard[5][4] = BLACK; -} - -static void -report(struct OthelloData *od) -{ - int i, j; - - od->number[0] = od->number[1] = 0; - for (i = 1; i <= 8; i++) - for (j = 1; j <= 8; j++) - if (od->nowboard[i][j] == BLACK) - od->number[0]++; - else if (od->nowboard[i][j] == WHITE) - od->number[1]++; - move(3, 60); - outs(cuser.userid); - move(3, 72); - prints(": %02d", od->number[0]); - move(4, 60); - prints("電腦 : %02d", od->number[1]); -} - -static int -EVL(struct OthelloData *od, char chessboard[][10], int color, int table_number) -{ - int points = 0, a, b; - for (a = 1; a <= 8; a++) - for (b = 1; b <= 8; b++) - if (chessboard[a][b] > HINT) { - if (chessboard[a][b] == BLACK) - points += od->evaltable[table_number][a][b]; - else - points -= od->evaltable[table_number][a][b]; - } - return ((color == BLACK) ? points : -points); -} - -static int -alphabeta(struct OthelloData *od, int alpha, int beta, int level, char chessboard[][10], - int thinkstep, int color, int table) -{ - int i, j, k, flag = 1; - char tempboard[10][10]; - if (level == thinkstep + 1) - return EVL(od, chessboard, (level & 1 ? color : ((color - 2) ^ 1) + 2), - table); - for (i = 1; i <= 8; i++) { - for (j = 1; j <= 8; j++) { - if (if_can_put(i, j, color, chessboard)) { - flag = 0; - memcpy(tempboard, chessboard, sizeof(char) * 100); - eat(i, j, color, tempboard); - - k = alphabeta(od, alpha, beta, level + 1, tempboard, thinkstep, - ((color - 2) ^ 1) + 2, table); - if (((level & 1) && k > alpha)) - alpha = k; - else if (!(level & 1) && k < beta) - beta = k; - if (alpha >= beta) - break; - } - } - } - if (flag) - return EVL(od, chessboard, color, table); - return ((level & 1) ? alpha : beta); -} - -static int -Computer(struct OthelloData *od, int thinkstep, int table) -{ - int i, j, maxi = 0, maxj = 0, level = 1; - char chessboard[10][10]; - int alpha = -10000, k; - if ((od->number[0] + od->number[1]) > 44) - table = NR_TABLE; - for (i = 1; i <= 8; i++) - for (j = 1; j <= 8; j++) { - if (if_can_put(i, j, WHITE, od->nowboard)) { - memcpy(chessboard, od->nowboard, sizeof(char) * 100); - eat(i, j, WHITE, chessboard); - k = alphabeta(od, alpha, 10000, level + 1, chessboard, thinkstep, - BLACK, table); - if (k > alpha) { - alpha = k; - maxi = i; - maxj = j; - } - } - } - if (alpha != -10000) { - eat(maxi, maxj, WHITE, od->nowboard); - od->pass = 0; - od->nowx = maxi; - od->nowy = maxj; - } else { - move(23, 30); - outs("電腦放棄這一步棋!!"); - od->pass++; - if (od->pass == 2) { - move(23, 24); - outs(" "); - end_of_game(od, 0); - return false; - } - igetch(); - move(23, 24); - outs(" "); - } - return true; -} - -static int -choose(void) -{ - char thinkstep[2]; - - move(2, 0); - outs("請選擇難度:"); - move(5, 0); - outs("[0] 離開\n"); - outs("(1) CD-65\n");/* 想 1 步 */ - outs("(2) 嬰兒\n"); /* 想 3 步 */ - outs("(3) 小孩\n"); /* 想 4 步 */ - do { - if (getdata(4, 0, "請選擇一個對象和您對打:(1~3)", - thinkstep, sizeof(thinkstep), LCECHO) == 0 || - thinkstep[0] == '0') - return 0; - - } while (thinkstep[0] < '1' || thinkstep[0] > '3'); - clear(); - switch (thinkstep[0]) { - case '2': - thinkstep[0] = '3'; - break; - case '3': - thinkstep[0] = '4'; - break; - default: - thinkstep[0] = '1'; - break; - } - return atoi(thinkstep); -} - -#define lockreturn0(unmode, state) if(lockutmpmode(unmode, state)) return 0 - -int -othello_main(void) -{ - struct OthelloData *od; - - lockreturn0(OTHELLO, LOCK_MULTI); - - od=(struct OthelloData*)malloc(sizeof(struct OthelloData)); - if(od==NULL) { - unlockutmpmode(); - return 0; - } - - clear(); - init(od); - od->think = choose(); - if (!od->think) - { - unlockutmpmode(); - free(od); - return 0; - } - showtitle("單人黑白棋", BBSName); - printboard(od); - od->which_table = random() % NR_TABLE; - while (true) { - move(STARTX - 1, 30); - outs("輪到你下了..."); - if (!player(od, BLACK)) - break; - report(od); - othello_redraw(od); - if (od->number[0] + od->number[1] == 64) { - end_of_game(od, 0); - break; - } - move(STARTX - 1, 30); - outs("電腦思考中..."); - refresh(); - if (!Computer(od, od->think, od->which_table)) - break; - report(od); - othello_redraw(od); - if (od->number[0] + od->number[1] == 64) { - end_of_game(od, 0); - break; - } - } - more(LOGFILE, YEA); - unlockutmpmode(); - free(od); - return 1; -} |