【C語言】五子棋(c語言實現)

這里寫目錄標題

  • 最終效果
  • 菜單打印函數
  • 棋盤的初始化和打印
  • 人人對戰
    • 落子判空函數
    • 悔棋函數
    • 判勝負函數
    • 人人對戰
  • 人機對戰
    • 一是將直接調用rand生成隨機值,這就不可控
    • 二是根據棋子贏面來判斷哪里落子最好
  • 如果選擇退出程序直接exit就行
  • 主函數調用邏輯
  • 源代碼

在這里插入圖片描述

最終效果

五子棋c語言實現

菜單打印函數

使用這個函數來接收用戶選擇的模式,并通過返回值返回。
邏輯是使用一個死循環來打印,根據玩家輸入的數來判斷進入什么模式,輸入錯誤數字就不出循環,正確就出循環。

int menu()
{int choice = -1;while (1){printf("----------------歡迎使用五子棋------------------------\n");printf("-                 請選擇模式                         -\n");printf("-                    1.人-人對戰游戲                 -\n");printf("-                    2.人-機對戰游戲                 -\n");printf("-                    0.退出游戲                      -\n");printf("------------------------------------------------------\n");printf("------------------------------------------------------\n");scanf("%d", &choice);if (choice > 4 || choice < 0)printf("錯誤輸入");elsebreak;}return choice;
}

棋盤的初始化和打印

在這個函數中將表示棋盤的二維數組初始化為空狀態,并通過棋盤數組的只來打印棋盤。打印棋盤時用到的符號:┏ ┳ ┓┣ ╋ ┫┗ ┻ ┛。要注意有些地方添加━和空格來控制打印的棋盤是正確的。
里面每一次打印都調用draw_chessman這個函數,在這個函數中將根據數組值來判斷如何打印。

//繪制棋子
void draw_chessman(int type, char* tableline) {if (type == WHITE)printf(" ●");if (type == BLACK)printf(" ○");if (type == NO)printf("%s", tableline);
}

打印棋盤的邏輯就是因為沒能設置光標坐標那就只有一行一行打印然后根據邊界行列值來判斷。
如果要看如何打印改變光標可以參考這篇文章win32 API

void initMap(int map[N + 1][N + 1])
{//第一行和第一列顯示數字for (int i = 0; i < N + 1; i++){map[0][i] = i;map[i][0] = i;if (i >= 10){map[0][i] = i - 10;map[i][0] = i - 10;}}for (int i = 0; i < N + 1; i++){//打印第一行數字if (i == 0){for (int j = 0; j < N + 1; j++){printf("%-2d", map[0][j]);}printf("\n");}//打印第一行棋盤else if (i == 1){for (int j = 0; j < N + 1; j++){if (j == 0)printf("%d", map[i][j]);else if (j == 1)draw_chessman(map[i][j], " ┏");else if (j == N)draw_chessman(map[i][j], "━┓");elsedraw_chessman(map[i][j], "━┳");}printf("\n");}//打印最后一行else if (i == N){for (int j = 0; j < N + 1; j++){if (j == 0)printf("%d", map[i][j]);else if (j == 1)draw_chessman(map[i][j], " ┗");else if (j == N)draw_chessman(map[i][j], "━┛");elsedraw_chessman(map[i][j], "━┻");}printf("\n");}else{for (int j = 0; j < N + 1; j++){if (j == 0)printf("%d", map[i][j]);else if (j == 1)draw_chessman(map[i][j], " ┣");else if (j == N)draw_chessman(map[i][j], "━┫");elsedraw_chessman(map[i][j], "━╋");}printf("\n");}}
}

人人對戰

人人對戰邏輯中就是先讓黑方下棋,輸入坐標,輸入錯誤就再次輸入(死循環實現),將該坐標的二維數組值變為黑,然后讓其選擇悔不悔棋,我實現的是只要1是悔棋其他數字就是不悔棋。執行完不悔棋后就判斷是否勝利,如果勝就跳出選擇是否重來一局,如果沒勝就白棋下執行相同邏輯。

落子判空函數

在這個函數中判斷坐標代表的二維數組值是不是空,不是就重新輸入坐標。

void judgeEmpty(int map[][N + 1], int x, int y, int goal)
{while (1){if (map[x][y] != NO){printf("已有棋子,重新輸入\n");scanf("%d%d", &x, &y);}else{map[x][y] = goal;initMap(map);break;}}
}

悔棋函數

該函數里面就是根據用戶選擇,如果悔棋然后將剛才的地方的數組值變回空。

int retract(int map[][N + 1], int x, int y)
{int choice = -1;printf("是否悔棋:是1\n");scanf("%d", &choice);if (choice == 1){map[x][y] = NO;initMap(map);}return choice;
}

執行完不悔棋后就判斷是否勝利

判勝負函數

這個函數就是將下的這個棋子的橫豎斜方向判勝負。(沒有判斷和棋情況),如果要判斷就是二維數組全不為空狀態,使用遍歷判斷就行。

int judgeWin(int map[][N + 1], int x, int y)
{for (int i = 1; i < N + 1; i++){for (int j = 1; j < N + 1; j++){if (j < N + 1 - 4 && (map[i][j] == BLACK || map[i][j] == WHITE))//橫{if (map[i][j] == map[i][j + 1]&& map[i][j + 1] == map[i][j + 2]&& map[i][j + 2] == map[i][j + 3]&& map[i][j + 3] == map[i][j + 4])return map[i][j];}if (i < N + 1 - 4 && (map[i][j] == BLACK || map[i][j] == WHITE))//豎{if (map[i][j] == map[i + 1][j]&& map[i + 1][j] == map[i + 2][j]&& map[i + 2][j] == map[i + 3][j]&& map[i + 3][j] == map[i + 4][j])return map[i][j];}if (i < N + 1 - 4 && j < N + 1 - 4 && (map[i][j] == BLACK || map[i][j] == WHITE))//右下_{if (map[i][j] == map[i + 1][j + 1]&& map[i + 1][j + 1] == map[i + 2][j + 2]&& map[i + 2][j + 2] == map[i + 3][j + 3]&& map[i + 3][j + 3] == map[i + 4][j + 4])return map[i][j];}if (i > 4 && j > 4 && (map[i][j] == BLACK || map[i][j] == WHITE))//右上{if (map[i][j] == map[i - 1][j - 1]&& map[i - 1][j - 1] == map[i - 2][j - 2]&& map[i - 2][j - 2] == map[i - 3][j - 3]&& map[i - 3][j - 3] == map[i - 4][j - 4])return map[i][j];}}}return NO;
}

人人對戰

void peopleFight(int map[][N + 1])
{printf("--------人-人對戰---------------\n");initMap(map);while (1){int x = -1;int y = -1;black:while (1){printf("黑方落子\n");printf("請輸入要落下的坐標現在棋盤為%d*%d\n", N, N);scanf("%d%d", &x, &y);if (x < 0 || x > N || y < 0 || y > N)printf("錯誤輸入\n");elsebreak;}judgeEmpty(map, x, y, BLACK);if (retract(map, x, y) == 1)goto black;//判斷勝利int ret = judgeWin(map, x, y);if (ret == BLACK){printf("黑方獲勝\n");return;}else if (ret == WHITE){printf("白方獲勝\n");return;}white:while (1){printf("白方落子\n");printf("請輸入要落下的坐標現在棋盤為%d*%d\n", N, N);scanf("%d%d", &x, &y);if (x < 0 || x > N || y < 0 || y > N)printf("錯誤輸入\n");elsebreak;}judgeEmpty(map, x, y, WHITE);if (retract(map, x, y) == 1)goto white;//判斷勝利ret = judgeWin(map, x, y);if (ret == BLACK){printf("黑方獲勝\n");return;}else if (ret == WHITE){printf("白方獲勝\n");return;}}
}

人機對戰

在這個函數中用戶選擇落子方,然后執行邏輯與人人對戰一樣。
但是電腦生成棋子提供兩種選擇:

一是將直接調用rand生成隨機值,這就不可控

方法一這樣寫對棋子的位置生成是很不可控的,會讓機器隨機亂落子。

void machine(int map[][N + 1])
{printf("--------人-機對戰---------------\n");srand(time(NULL));int choice = -1;printf("請輸入你執黑棋還是白棋,黑1,白2\n");scanf("%d", &choice);if (choice == 1){while (1){int x = -1;int y = -1;black:while (1){printf("黑方落子\n");printf("請輸入要落下的坐標現在棋盤為%d*%d\n", N, N);scanf("%d%d", &x, &y);if (x < 0 || x > N || y < 0 || y > N)printf("錯誤輸入\n");elsebreak;}judgeEmpty(map, x, y, BLACK);//判斷勝利int ret = judgeWin(map, x, y);if (ret == BLACK){printf("黑方獲勝\n");return;}else if (ret == WHITE){printf("白方獲勝\n");return;}if (retract(map, x, y) == 1)goto black;next:x = rand() % 15 + 1;y = rand() % 15 + 1;if (map[x][y] != NO)goto next;judgeEmpty(map, x, y, WHITE);//判斷勝利ret = judgeWin(map, x, y);if (ret == BLACK){printf("黑方獲勝\n");return;}else if (ret == WHITE){printf("白方獲勝\n");return;}}}else if (choice == 2){while (1){int x = -1;int y = -1;next2:x = rand() % 15 + 1;y = rand() % 15 + 1;if (map[x][y] != NO)goto next2;judgeEmpty(map, x, y, BLACK);//判斷勝利int ret = judgeWin(map, x, y);if (ret == BLACK){printf("黑方獲勝\n");return;}else if (ret == WHITE){printf("白方獲勝\n");return;}white:while (1){printf("白方落子\n");printf("請輸入要落下的坐標現在棋盤為%d*%d\n", N, N);scanf("%d%d", &x, &y);if (x < 0 || x > N || y < 0 || y > N)printf("錯誤輸入\n");elsebreak;}judgeEmpty(map, x, y, WHITE);//判斷勝利ret = judgeWin(map, x, y);if (ret == BLACK){printf("黑方獲勝\n");return;}else if (ret == WHITE){printf("白方獲勝\n");return;}if (retract(map, x, y) == 1)goto white;}}}

二是根據棋子贏面來判斷哪里落子最好

這樣實現就會讓機器落子一直是去圍堵你的棋子,雖然還是很垃圾,但是比方法一好多了。

void AIjudge(int color, int map[N+1][N+1])
{int num = 1, left = 0, right = 0;int n, m, score = 0, max = 0;int dx, dy;for (int i = 1; i < N+1; i++){for (int j = 1; j < N+1; j++){score = 0;if (map[i][j] != 0)continue;else{dx = 1, dy = 0, n = i, m = j;while (1)//水平向右{n += dx, m += dy;if (map[n][m] == 0){right = 0; break;}else if (map[n][m] != color || n > 15){right++; break;}else if (num < 5) { num++; }}dx = -1, dy = 0;while (1) {//水平向左n += dx; m += dy;if (map[n][m] == 0) { left = 0; break; }else if (map[n][m] != color || n < 1) { left++; break; }else if (num < 5) { num++; }}score += Data(num, right + left);//用data來算分數,并用score來記錄//  |方向num = 1; right = 0, left = 0;//每一次改變方向要重置這些變量dx = 0; dy = -1; n = i; m = j;//向上while (1) {n += dx; m += dy;if (map[n][m] == 0) { left = 0; break; }else if (map[n][m] != color || m < 1) { left++; break; }else if (num < 5) { num++; }}//向下dx = 0; dy = 1; n = i; m = j;while (1) {n += dx; m += dy;if (map[n][m] == 0) { right = 0; break; }else if (map[n][m] != color || m > 15) { right++; break; }else if (num < 5) { num++; }}score += Data(num, right + left);//  \方向num = 1; right = 0, left = 0;dx = 1; dy = 1; n = i; m = j;//向右下while (1) {n += dx; m += dy;if (map[n][m] == 0) { right = 0; break; }else if (map[n][m] != color || m > 15 || n > 15) { right++; break; }else if (num < 5) { num++; }}//向左上dx = -1; dy = -1; n = i; m = j;while (1) {n += dx; m += dy;if (n > 0 && m > 0 && map[n][m] == 0) { left = 0; break; }else if ((n > 0 && m > 0 && map[n][m] != color) || m < 1 || n < 1) { left++; break; }else if (num < 5) { num++; }}score += Data(num, right + left);//  /方向`num = 1; right = 0, left = 0;dx = 1; dy = -1; n = i; m = j;//向右上while (1) {n += dx; m += dy;if (map[n][m] == 0) { right = 0; break; }else if (map[n][m] != color || n > 15 || m < 1) { right++; break; }else if (num < 5) { num++; }}//向左下dx = -1; dy = 1; n = i; m = j;while (1) {n += dx; m += dy;if (n > 0 && m > 0 && map[n][m] == 0) { left = 0; break; }else if ((n > 0 && m > 0 && map[n][m] != color) || n < 1 || m > 15) { left++; break; }else if (num < 5) { num++; }}score += Data(num, right + left);if (score > max) {//每一次用max保存分數,下一次比較,最后找出最大值max = score;position[0] = i;//用來保存每一次的位置和分數position[1] = j;position[2] = score;}}}}
}
int Data(int num, int count)
{switch (num){case 1:	if (count == 0)//活一:表示在該處落子,就只有這一個棋子,兩邊都沒有阻擋(邊界或對方的棋子)優勢較大return 2;else if (count == 1)//沖一:表示在該處落子,就只有這一個棋子,兩邊有一種阻擋(邊界或對方的棋子)優勢較小return 1;else return 0;break;case 2:if (count == 0)//活二;接下來都同理活一和沖一return 20;else if (count == 1)//沖二return 10;else return 0;break;case 3:if (count == 0)//活三return 300;else if (count == 1)//沖三return 50;else return 0;break;case 4:if (count == 0)//活四return 4000;else if (count == 1)//沖四return 1000;else return 0;break;case 5://五return 5000;break;default:return 0;break;}
}
void machine(int map[][N + 1])
{printf("--------人-機對戰---------------\n");int choice = -1;do {printf("請輸入你執黑棋還是白棋,黑1,白2\n");scanf("%d", &choice);} while (choice != 1 && choice != 2);initMap(map);if (choice == 1){while (1){int x = -1;int y = -1;black:while (1){printf("黑方落子\n");printf("現在棋盤為%d*%d請輸入要落下的坐標x y\n", N, N);scanf("%d%d", &x, &y);if (x < 0 || x > N || y < 0 || y > N)printf("錯誤輸入\n");elsebreak;}judgeEmpty(map, x, y, BLACK);if (retract(map, x, y)){map[x][y] = 0;initMap(map);goto black;}int ret = judgeWin(map, x, y);if (ret == BLACK)       //判斷勝利break;int old_max = 0, new_max = 0, n = 0, m = 0;int AIx = -1, AIy = -1;AIjudge(1, map);//判斷黑子的優勢位置old_max = position[2];//保存該位置分數AIx = position[0]; AIy = position[1];//保存該位置的坐標,注意行列和xy軸的對應關系position[0] = 0, position[1] = 0, position[2] = 0;AIjudge(-1, map);//判斷白子的優勢位置new_max = position[2];//保存分數if (new_max >= old_max) //判斷哪個位置的分數大,從而判斷是堵截還是進攻{AIx = position[0]; AIy = position[1];}judgeEmpty(map, AIx, AIy, WHITE);ret = judgeWin(map, x, y);if (ret == WHITE)       //判斷勝利break;}}else if (choice == 2){while (1){int x = -1, y = -1;int old_max = 0, new_max = 0, n = 0, m = 0;int AIx = -1, AIy = -1;AIjudge(1, map);//判斷黑子的優勢位置old_max = position[2];//保存該位置分數AIx = position[0]; AIy = position[1];//保存該位置的坐標,注意行列和xy軸的對應關系position[0] = 0, position[1] = 0, position[2] = 0;AIjudge(-1, map);//判斷白子的優勢位置new_max = position[2];//保存分數if (new_max >= old_max) //判斷哪個位置的分數大,從而判斷是堵截還是進攻{AIx = position[0]; AIy = position[1];}judgeEmpty(map, AIx, AIy, BLACK);int ret = judgeWin(map, x, y);if (ret == BLACK)       //判斷勝利 break;white:while (1){printf("白方落子\n");printf("現在棋盤為%d*%d請輸入要落下的坐標x y\n", N, N);scanf("%d,%d", &x, &y);if (x < 0 || x > N || y < 0 || y > N)printf("錯誤輸入\n");elsebreak;}judgeEmpty(map, x, y, WHITE);if (retract(map, x, y)){map[x][y] = 0;initMap(map);goto white;}ret = judgeWin(map, x, y);if (ret == WHITE)       //判斷勝利break;}}}

如果選擇退出程序直接exit就行

主函數調用邏輯

用死循環調用,然后根據menu返回值通過switch-case來調用相應模式函數,最后在讓用戶選擇是否再來一局,如果再來一局就不出循環,不再來就出循環。

int main()
{while (1){int map[N + 1][N + 1] = { 0 };int choice = menu();switch (choice){case 1://調用人人對打peopleFight(map);break;case 2://調用人機對打machine(map);break;case 0:printf("退出成功\n");exit(0);break;}int a = 0;printf("是否再來一盤:是1,不是0\n");scanf("%d", &a);if (a == 0)break;}return 0;
}

源代碼

源碼呈上,為方便復制寫在同一個文件之下,可以多文件進行。

# define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include <stdlib.h>
#include<time.h>
#define N 15 //表示棋盤的行列
#define NO 0 //表示沒下子的狀態
#define BLACK 1
#define WHITE -1
//棋盤初始化函數
void initMap(int map[N + 1][N + 1]);
//落子函數
void judgeEmpty(int map[][N + 1], int x, int y, int goal);
//人人對打
void peopleFight(int map[][N + 1]);
//判斷勝利
int judgeWin(int map[][N + 1], int x, int y);
//悔棋
int retract(int map[][N + 1], int x, int y);
//人機對打
void machine(int map[][N + 1]);
//打印菜單并返回選擇的模式
int menu();
void AIjudge(int color, int map[N + 1][N + 1]);
int Data(int num, int count);
int position[3];int main()
{while (1){int map[N + 1][N + 1] = { 0 };int choice = menu();switch (choice){case 1://調用人人對打peopleFight(map);break;case 2://調用人機對打machine(map);break;case 0:printf("退出成功\n");exit(0);break;}int a = 0;printf("是否再來一盤:是1,不是0\n");scanf("%d", &a);if (a == 0)break;}return 0;
}
int menu()
{int choice = -1;while (1){printf("----------------歡迎使用五子棋------------------------\n");printf("-                 請選擇模式                         -\n");printf("-                    1.人-人對戰游戲                 -\n");printf("-                    2.人-機對戰游戲                 -\n");printf("-                    0.退出游戲                      -\n");printf("------------------------------------------------------\n");printf("------------------------------------------------------\n");scanf("%d", &choice);if (choice > 4 || choice < 0)printf("錯誤輸入");elsebreak;}return choice;
}void judgeEmpty(int map[][N + 1], int x, int y, int goal)
{while (1){if (map[x][y] != NO){printf("已有棋子,重新輸入\n");scanf("%d%d", &x, &y);}else{map[x][y] = goal;initMap(map);break;}}
}int judgeWin(int map[][N + 1], int x, int y)
{for (int i = 1; i < N + 1; i++){for (int j = 1; j < N + 1; j++){if (j < N + 1 - 4 && (map[i][j] == BLACK || map[i][j] == WHITE))//橫{if (map[i][j] == map[i][j + 1]&& map[i][j + 1] == map[i][j + 2]&& map[i][j + 2] == map[i][j + 3]&& map[i][j + 3] == map[i][j + 4])return map[i][j];}if (i < N + 1 - 4 && (map[i][j] == BLACK || map[i][j] == WHITE))//豎{if (map[i][j] == map[i + 1][j]&& map[i + 1][j] == map[i + 2][j]&& map[i + 2][j] == map[i + 3][j]&& map[i + 3][j] == map[i + 4][j])return map[i][j];}if (i < N + 1 - 4 && j < N + 1 - 4 && (map[i][j] == BLACK || map[i][j] == WHITE))//右下_{if (map[i][j] == map[i + 1][j + 1]&& map[i + 1][j + 1] == map[i + 2][j + 2]&& map[i + 2][j + 2] == map[i + 3][j + 3]&& map[i + 3][j + 3] == map[i + 4][j + 4])return map[i][j];}if (i > 4 && j > 4 && (map[i][j] == BLACK || map[i][j] == WHITE))//右上{if (map[i][j] == map[i - 1][j - 1]&& map[i - 1][j - 1] == map[i - 2][j - 2]&& map[i - 2][j - 2] == map[i - 3][j - 3]&& map[i - 3][j - 3] == map[i - 4][j - 4])return map[i][j];}}}return NO;
}//繪制棋子
void draw_chessman(int type, char* tableline) {if (type == WHITE)printf(" ●");if (type == BLACK)printf(" ○");if (type == NO)printf("%s", tableline);
}void initMap(int map[N + 1][N + 1])
{//第一行和第一列顯示數字for (int i = 0; i < N + 1; i++){map[0][i] = i;map[i][0] = i;if (i >= 10){map[0][i] = i - 10;map[i][0] = i - 10;}}for (int i = 0; i < N + 1; i++){//打印第一行數字if (i == 0){for (int j = 0; j < N + 1; j++){printf("%-2d", map[0][j]);}printf("\n");}//打印第一行棋盤else if (i == 1){for (int j = 0; j < N + 1; j++){if (j == 0)printf("%d", map[i][j]);else if (j == 1)draw_chessman(map[i][j], " ┏");else if (j == N)draw_chessman(map[i][j], "━┓");elsedraw_chessman(map[i][j], "━┳");}printf("\n");}//打印最后一行else if (i == N){for (int j = 0; j < N + 1; j++){if (j == 0)printf("%d", map[i][j]);else if (j == 1)draw_chessman(map[i][j], " ┗");else if (j == N)draw_chessman(map[i][j], "━┛");elsedraw_chessman(map[i][j], "━┻");}printf("\n");}else{for (int j = 0; j < N + 1; j++){if (j == 0)printf("%d", map[i][j]);else if (j == 1)draw_chessman(map[i][j], " ┣");else if (j == N)draw_chessman(map[i][j], "━┫");elsedraw_chessman(map[i][j], "━╋");}printf("\n");}}
}//void machine(int map[][N + 1])
//{
//    printf("--------人-機對戰---------------\n");
//    srand(time(NULL));
//    int choice = -1;
//    printf("請輸入你執黑棋還是白棋,黑1,白2\n");
//    scanf("%d", &choice);
//    if (choice == 1)
//    {
//        while (1)
//        {
//            int x = -1;
//            int y = -1;
//        black:
//            while (1)
//            {
//                printf("黑方落子\n");
//                printf("請輸入要落下的坐標現在棋盤為%d*%d\n", N, N);
//                scanf("%d%d", &x, &y);
//                if (x < 0 || x > N || y < 0 || y > N)
//                    printf("錯誤輸入\n");
//                else
//                    break;
//            }
//            judgeEmpty(map, x, y, BLACK);
//            //判斷勝利
//            int ret = judgeWin(map, x, y);
//            if (ret == BLACK)
//            {
//                printf("黑方獲勝\n");
//                return;
//            }
//            else if (ret == WHITE)
//            {
//                printf("白方獲勝\n");
//                return;
//            }
//            if (retract(map, x, y) == 1)
//                goto black;
//        next:
//            x = rand() % 15 + 1;
//            y = rand() % 15 + 1;
//            if (map[x][y] != NO)
//                goto next;
//            judgeEmpty(map, x, y, WHITE);
//            //判斷勝利
//            ret = judgeWin(map, x, y);
//            if (ret == BLACK)
//            {
//                printf("黑方獲勝\n");
//                return;
//            }
//            else if (ret == WHITE)
//            {
//                printf("白方獲勝\n");
//                return;
//            }
//        }
//    }
//    else if (choice == 2)
//    {
//        while (1)
//        {
//            int x = -1;
//            int y = -1;
//        next2:
//            x = rand() % 15 + 1;
//            y = rand() % 15 + 1;
//            if (map[x][y] != NO)
//                goto next2;
//            judgeEmpty(map, x, y, BLACK);
//            //判斷勝利
//            int ret = judgeWin(map, x, y);
//            if (ret == BLACK)
//            {
//                printf("黑方獲勝\n");
//                return;
//            }
//            else if (ret == WHITE)
//            {
//                printf("白方獲勝\n");
//                return;
//            }
//        white:
//            while (1)
//            {
//                printf("白方落子\n");
//                printf("請輸入要落下的坐標現在棋盤為%d*%d\n", N, N);
//                scanf("%d%d", &x, &y);
//                if (x < 0 || x > N || y < 0 || y > N)
//                    printf("錯誤輸入\n");
//                else
//                    break;
//            }
//            judgeEmpty(map, x, y, WHITE);
//            //判斷勝利
//            ret = judgeWin(map, x, y);
//            if (ret == BLACK)
//            {
//                printf("黑方獲勝\n");
//                return;
//            }
//            else if (ret == WHITE)
//            {
//                printf("白方獲勝\n");
//                return;
//            }
//            if (retract(map, x, y) == 1)
//                goto white;
//
//        }
//    }
//
//}void peopleFight(int map[][N + 1])
{printf("--------人-人對戰---------------\n");initMap(map);while (1){int x = -1;int y = -1;black:while (1){printf("黑方落子\n");printf("請輸入要落下的坐標現在棋盤為%d*%d\n", N, N);scanf("%d%d", &x, &y);if (x < 0 || x > N || y < 0 || y > N)printf("錯誤輸入\n");elsebreak;}judgeEmpty(map, x, y, BLACK);if (retract(map, x, y) == 1)goto black;//判斷勝利int ret = judgeWin(map, x, y);if (ret == BLACK){printf("黑方獲勝\n");return;}else if (ret == WHITE){printf("白方獲勝\n");return;}white:while (1){printf("白方落子\n");printf("請輸入要落下的坐標現在棋盤為%d*%d\n", N, N);scanf("%d%d", &x, &y);if (x < 0 || x > N || y < 0 || y > N)printf("錯誤輸入\n");elsebreak;}judgeEmpty(map, x, y, WHITE);if (retract(map, x, y) == 1)goto white;//判斷勝利ret = judgeWin(map, x, y);if (ret == BLACK){printf("黑方獲勝\n");return;}else if (ret == WHITE){printf("白方獲勝\n");return;}}
}int retract(int map[][N + 1], int x, int y)
{int choice = -1;printf("是否悔棋:是1\n");scanf("%d", &choice);if (choice == 1){map[x][y] = NO;initMap(map);}return choice;
}
void AIjudge(int color, int map[N+1][N+1])
{int num = 1, left = 0, right = 0;int n, m, score = 0, max = 0;int dx, dy;for (int i = 1; i < N+1; i++){for (int j = 1; j < N+1; j++){score = 0;if (map[i][j] != 0)continue;else{dx = 1, dy = 0, n = i, m = j;while (1)//水平向右{n += dx, m += dy;if (map[n][m] == 0){right = 0; break;}else if (map[n][m] != color || n > 15){right++; break;}else if (num < 5) { num++; }}dx = -1, dy = 0;while (1) {//水平向左n += dx; m += dy;if (map[n][m] == 0) { left = 0; break; }else if (map[n][m] != color || n < 1) { left++; break; }else if (num < 5) { num++; }}score += Data(num, right + left);//用data來算分數,并用score來記錄//  |方向num = 1; right = 0, left = 0;//每一次改變方向要重置這些變量dx = 0; dy = -1; n = i; m = j;//向上while (1) {n += dx; m += dy;if (map[n][m] == 0) { left = 0; break; }else if (map[n][m] != color || m < 1) { left++; break; }else if (num < 5) { num++; }}//向下dx = 0; dy = 1; n = i; m = j;while (1) {n += dx; m += dy;if (map[n][m] == 0) { right = 0; break; }else if (map[n][m] != color || m > 15) { right++; break; }else if (num < 5) { num++; }}score += Data(num, right + left);//  \方向num = 1; right = 0, left = 0;dx = 1; dy = 1; n = i; m = j;//向右下while (1) {n += dx; m += dy;if (map[n][m] == 0) { right = 0; break; }else if (map[n][m] != color || m > 15 || n > 15) { right++; break; }else if (num < 5) { num++; }}//向左上dx = -1; dy = -1; n = i; m = j;while (1) {n += dx; m += dy;if (n > 0 && m > 0 && map[n][m] == 0) { left = 0; break; }else if ((n > 0 && m > 0 && map[n][m] != color) || m < 1 || n < 1) { left++; break; }else if (num < 5) { num++; }}score += Data(num, right + left);//  /方向`num = 1; right = 0, left = 0;dx = 1; dy = -1; n = i; m = j;//向右上while (1) {n += dx; m += dy;if (map[n][m] == 0) { right = 0; break; }else if (map[n][m] != color || n > 15 || m < 1) { right++; break; }else if (num < 5) { num++; }}//向左下dx = -1; dy = 1; n = i; m = j;while (1) {n += dx; m += dy;if (n > 0 && m > 0 && map[n][m] == 0) { left = 0; break; }else if ((n > 0 && m > 0 && map[n][m] != color) || n < 1 || m > 15) { left++; break; }else if (num < 5) { num++; }}score += Data(num, right + left);if (score > max) {//每一次用max保存分數,下一次比較,最后找出最大值max = score;position[0] = i;//用來保存每一次的位置和分數position[1] = j;position[2] = score;}}}}
}
int Data(int num, int count)
{switch (num){case 1:	if (count == 0)//活一:表示在該處落子,就只有這一個棋子,兩邊都沒有阻擋(邊界或對方的棋子)優勢較大return 2;else if (count == 1)//沖一:表示在該處落子,就只有這一個棋子,兩邊有一種阻擋(邊界或對方的棋子)優勢較小return 1;else return 0;break;case 2:if (count == 0)//活二;接下來都同理活一和沖一return 20;else if (count == 1)//沖二return 10;else return 0;break;case 3:if (count == 0)//活三return 300;else if (count == 1)//沖三return 50;else return 0;break;case 4:if (count == 0)//活四return 4000;else if (count == 1)//沖四return 1000;else return 0;break;case 5://五return 5000;break;default:return 0;break;}
}
void machine(int map[][N + 1])
{printf("--------人-機對戰---------------\n");int choice = -1;do {printf("請輸入你執黑棋還是白棋,黑1,白2\n");scanf("%d", &choice);} while (choice != 1 && choice != 2);initMap(map);if (choice == 1){while (1){int x = -1;int y = -1;black:while (1){printf("黑方落子\n");printf("現在棋盤為%d*%d請輸入要落下的坐標x y\n", N, N);scanf("%d%d", &x, &y);if (x < 0 || x > N || y < 0 || y > N)printf("錯誤輸入\n");elsebreak;}judgeEmpty(map, x, y, BLACK);if (retract(map, x, y)){map[x][y] = 0;initMap(map);goto black;}int ret = judgeWin(map, x, y);if (ret == BLACK)       //判斷勝利break;int old_max = 0, new_max = 0, n = 0, m = 0;int AIx = -1, AIy = -1;AIjudge(1, map);//判斷黑子的優勢位置old_max = position[2];//保存該位置分數AIx = position[0]; AIy = position[1];//保存該位置的坐標,注意行列和xy軸的對應關系position[0] = 0, position[1] = 0, position[2] = 0;AIjudge(-1, map);//判斷白子的優勢位置new_max = position[2];//保存分數if (new_max >= old_max) //判斷哪個位置的分數大,從而判斷是堵截還是進攻{AIx = position[0]; AIy = position[1];}judgeEmpty(map, AIx, AIy, WHITE);ret = judgeWin(map, x, y);if (ret == WHITE)       //判斷勝利break;}}else if (choice == 2){while (1){int x = -1, y = -1;int old_max = 0, new_max = 0, n = 0, m = 0;int AIx = -1, AIy = -1;AIjudge(1, map);//判斷黑子的優勢位置old_max = position[2];//保存該位置分數AIx = position[0]; AIy = position[1];//保存該位置的坐標,注意行列和xy軸的對應關系position[0] = 0, position[1] = 0, position[2] = 0;AIjudge(-1, map);//判斷白子的優勢位置new_max = position[2];//保存分數if (new_max >= old_max) //判斷哪個位置的分數大,從而判斷是堵截還是進攻{AIx = position[0]; AIy = position[1];}judgeEmpty(map, AIx, AIy, BLACK);int ret = judgeWin(map, x, y);if (ret == BLACK)       //判斷勝利 break;white:while (1){printf("白方落子\n");printf("現在棋盤為%d*%d請輸入要落下的坐標x y\n", N, N);scanf("%d,%d", &x, &y);if (x < 0 || x > N || y < 0 || y > N)printf("錯誤輸入\n");elsebreak;}judgeEmpty(map, x, y, WHITE);if (retract(map, x, y)){map[x][y] = 0;initMap(map);goto white;}ret = judgeWin(map, x, y);if (ret == WHITE)       //判斷勝利break;}}}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/40230.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/40230.shtml
英文地址,請注明出處:http://en.pswp.cn/web/40230.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

‘艾’公益——微笑行動「廣安站」為艾祝福,讓笑起舞

艾多美“微笑行動”廣安站拉開帷幕 此次愛心幫助7名唇腭裂患兒 重新綻放微笑 艾多美“微笑行動”廣安站拉開帷幕 此次愛心幫助7名唇腭裂患兒 重新綻放微笑 不讓笑容留有缺憾 每個孩子都有微笑的權利 艾多美向唇腭裂兒童伸出援手 綻放笑容&#xff0c;擁抱全新的未來 2…

進程、程序、應用程序之間的關系

文章目錄 進程和程序進程和應用程序總結參考資料 進程和程序 程序&#xff1a;程序是存放在硬盤中的可執行文件&#xff0c;主要包括代碼指令和數據。程序本身是一個靜態的文件&#xff0c;只有在被操作系統加載到內存中并執行時才會變成進程。 進程&#xff1a;進程是程序在…

衛星軌道平面簡單認識

目錄 一、軌道平面 1.1 軌道根數 1.2 應用考慮 二、分類 2.1 根據運行高度 2.2 根據運行軌跡偏心率 2.3 根據傾角大小 三、衛星星座中的軌道平面 四、設計軌道平面的考慮因素 一、軌道平面 1.1 軌道根數 軌道平面是定義衛星或其他天體繞行另一天體運動的平面。這個平…

第十六章 Qt的文件處理操作詳解

目錄 一、基本文件操作 二、二進制文件讀寫 三、文本文件讀寫 四、操作例子 1、QTextStream的流操作符 一、基本文件操作 文件操作是應用程序必不可少的部分。Qt 作為一個通用開發庫,提供了跨平臺的文件操作能力。在所有的 I/O 設備中,文件 I/O 是最重要的部分之…

TF-IDF和BM25原理和區別

TF-IDF TF-IDF是TF&#xff08;詞頻&#xff0c;Term Frequency&#xff09;和IDF&#xff08;逆文檔頻率&#xff0c;Inverse Document Frequency&#xff09;的乘積。我們先來看他們分別是怎么計算的&#xff1a; TF的計算有多種方式&#xff0c;常見的是 除以文章總詞數是…

從CPU的視角看C++的構造函數和this指針

從匯編角度&#xff0c;清晰的去看構造函數和this指針到底是個什么東西呢&#xff1f;也許可以解決你的一點小疑問 首先寫一個很簡單的代碼demo&#xff1a; class A{ public:int a;A(){;}void seta(int _a){a_a;}A* getA(){return this;} };int fun1(int px){return px; }in…

【FreeRTOS】同步互斥與通信 有缺陷的同步示例

目錄 1 同步互斥與通信1.1 同步互斥與通信概述1.2 同步與互斥的概念1.3 同步的例子&#xff1a;有缺陷1.4 freertos.c源碼3. 互斥的例子&#xff1a;有缺陷4. 通信的例子&#xff1a;有缺陷5. FreeRTOS的解決方案 1 同步互斥與通信 1.1 同步互斥與通信概述 參考《FreeRTOS入門…

搞錢四步:干活、出名、破圈、整合

搞錢這事兒&#xff0c;說起來有四步&#xff1a;干活、出名、破圈、整合。 咱們現在這個時代&#xff0c;誰要是能把自尊心放一邊&#xff0c;勇敢站到舞臺上展示才華&#xff0c;變現那是分鐘的事兒。 只要你敢承認自己想要財富&#xff0c;并且不停地使用正確的方法論&…

python語句前面有一個$是什么意思

“$”是匯編語言中的一個預定義符號&#xff0c;等價于當前正匯編到的段的當前偏移值。例如&#xff1a;指令“jmp $3”中的“$”表示當前這條指令在代碼段中的偏移量。 代表當前指令的地址&#xff0c;如&#xff1a; data segment str1 db a,b,c,d leng equ $-str 就是當前地…

JVM專題之性能優化

運行時優化 方法內聯 > 方法內聯,是指 **JVM在運行時將調用次數達到一定閾值的方法調用替換為方法體本身** ,從而消除調用成本,并為接下來進一步的代碼性能優化提供基礎,是JVM的一個重要優化手段之一。 > > **注:** > > * **C++的inline屬于編譯后內聯,…

數據庫實訓復習(1)

目錄 一、關于表結構的相關操作&#xff08;與表中字段的數據操作有區別&#xff09; &#xff08;1&#xff09;往已有的表中添加字段 &#xff08;2&#xff09;修改表中已有字段的數據類型 &#xff08;3&#xff09;修改已有的表中的字段名和字段類型 &#xff08;4&a…

TopK問題與堆排序

目錄 TopK問題&#xff1a; 定義&#xff1a; 應用場景&#xff1a; 搜索引擎&#xff1a; 推薦系統&#xff1a; 數據分析&#xff1a; 數據挖掘&#xff1a; TopK問題初階&#xff1a;&#xff08;數據量較小情況&#xff09; TopK問題進階&#xff1a;&#xff08;…

知名品牌因商標痛失市場:114家直營店山寨店7000多家!

奶茶知名品牌“鹿角巷”當年紅遍大江南北&#xff0c;是最早的新茶飲品牌&#xff0c;但是當年商標注冊存在問題&#xff0c;被同行奶茶品牌搶占了先機&#xff0c;發聲明“對大陸商標注冊細則不詳&#xff0c;在商標注冊過程中讓假店鉆了法律空檔”&#xff0c;最夸張的時候全…

qml required property

目錄 前言 示例代碼 創建一個自定義組件&#xff08;MyComponent.qml&#xff09; 使用自定義組件&#xff08;main.qml&#xff09; 解釋 運行效果 運行時錯誤示例 前言 在 QML 中&#xff0c;你可以使用 required 關鍵字來聲明一個屬性是必需的。這意味著在創建該對象…

如何用Python向PPT中批量插入圖片

辦公自動化辦公中&#xff0c;Python最大的優勢是可以批量操作&#xff0c;省去了用戶粘貼、復制、插入等繁瑣的操作。經常做PPT的朋友都知道&#xff0c;把圖片插入到PPT當中的固定位置是一個非常繁瑣的操作&#xff0c;往往調整圖片時耗費大量的時間和精力。如何能省時省力插…

【數據結構】使用C語言 從零實現一個棧的數據結構

棧 什么是棧&#xff1f;棧是一種特殊的線性表&#xff0c;它只能在在表尾進行插入和刪除操作。 棧的底部稱為棧底&#xff0c;頂部稱為棧頂&#xff0c;所有的操作只能在棧頂進行&#xff0c;也就是說&#xff0c;被壓在下方的元素&#xff0c;只能等待其上方的元素出棧之后…

LeetCode-簡單-回文數

給你一個整數 x &#xff0c;如果 x 是一個回文整數&#xff0c;返回 true &#xff1b;否則&#xff0c;返回 false 。 回文數 是指正序&#xff08;從左向右&#xff09;和倒序&#xff08;從右向左&#xff09;讀都是一樣的整數。 例如&#xff0c;121 是回文&#xff0c;…

windows啟動Docker閃退Docker desktop stopped

Windows啟動Docker閃退-Docker desktop stopped 電腦上很早就安裝有Docker了&#xff0c;但是有一段時間都沒有啟動了&#xff0c;今天想啟動啟動不起來了&#xff0c;打開沒幾秒就閃退&#xff0c;記錄一下解決方案。僅供參考 首先&#xff0c;參照其他解決方案&#xff0c;本…

Ubuntu20安裝mysql方法,適用于wsl

itopen組織1、提供OpenHarmony優雅實用的小工具2、手把手適配riscv qemu linux的三方庫移植3、未來計劃riscv qemu ohos的三方庫移植 小程序開發4、一切擁抱開源&#xff0c;擁抱國產化 一、Ubunt20安裝mysql 適用于wsl中安裝mysql sudo apt update# 查看可使用的安裝包…

【刷題匯總--游游的you、腐爛的蘋果、孩子們的游戲(圓圈中最后剩下的數)】

C日常刷題積累 今日刷題匯總 - day0051、游游的you1.1、題目1.2、思路1.3、程序實現 - 蠻力法1.4、程序實現 - 貪心(優化) 2、腐爛的蘋果2.1、題目2.2、思路2.3、程序實現 - bfs 3、孩子們的游戲(圓圈中最后剩下的數)3.1、題目3.2、思路3.3、程序實現 -- 環形鏈表3.4、程序實現…