#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <windows.h>
#include <time.h>
// 手动定义CP_GBK(解决未定义报错)
#ifndef CP_GBK
#define CP_GBK 936
#endif
// 棋盘尺寸与评分常量
#define BOARD_SIZE 15
#define MAX_SCORE 100000
#define MIN_SCORE -100000
// 难度枚举
typedef enum {
EASY, // 简单:随机落子+基础封堵
MEDIUM, // 中等:评分落子+优先封堵
HARD // 困难:深度评分+攻防最优
} Difficulty;
// 棋子类型定义
typedef enum {
EMPTY, // 空位置
BLACK, // 黑棋(玩家)
WHITE // 白棋(AI)
} ChessType;
// 全局变量
ChessType board[BOARD_SIZE][BOARD_SIZE]; // 棋盘数组
int currentX = 0, currentY = 0; // 玩家光标坐标
int gameOver = 0; // 游戏结束标记
int lastX = -1, lastY = -1; // 上一步落子位置(悔棋用)
Difficulty gameDiff = MEDIUM; // 默认难度:中等
// 重绘控制变量
int needRedraw = 1; // 标记是否需要重绘棋盘
int firstDraw = 1; // 控制首次清屏
// 设置控制台光标位置
void setCursorPos(int x, int y) {
COORD coord;
coord.X = x;
coord.Y = y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
}
// 隐藏控制台光标
void hideCursor() {
CONSOLE_CURSOR_INFO cci;
cci.bVisible = FALSE;
cci.dwSize = 1;
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cci);
}
// 选择游戏难度
void selectDifficulty() {
system("cls");
int select = 1; // 默认选中中等难度
printf("===================== 选择游戏难度 =====================\n");
printf("请按 ↑/↓ 选择难度,按 空格 确认\n");
printf("=======================================================\n");
while (1) {
setCursorPos(0, 4);
printf(select == 0 ? "→ 简单:AI随机落子,容易获胜\n" : " 简单:AI随机落子,容易获胜\n");
printf(select == 1 ? "→ 中等:AI智能封堵,有挑战性\n" : " 中等:AI智能封堵,有挑战性\n");
printf(select == 2 ? "→ 困难:AI攻防最优,难度较高\n" : " 困难:AI攻防最优,难度较高\n");
// 处理按键
if (_kbhit()) {
char key = _getch();
switch (key) {
case 'w': case 'W': case 72: // 上键(72是方向键ASCII)
select = (select - 1 + 3) % 3;
break;
case 's': case 'S': case 80: // 下键(80是方向键ASCII)
select = (select + 1) % 3;
break;
case ' ': // 确认选择
if (select == 0) gameDiff = EASY;
else if (select == 1) gameDiff = MEDIUM;
else gameDiff = HARD;
return;
}
}
Sleep(50);
}
}
// 初始化棋盘
void initBoard() {
// 清空棋盘
for (int i = 0; i < BOARD_SIZE; i++) {
for (int j = 0; j < BOARD_SIZE; j++) {
board[i][j] = EMPTY;
}
}
// 重置游戏状态
currentX = BOARD_SIZE / 2;
currentY = BOARD_SIZE / 2;
gameOver = 0;
lastX = lastY = -1;
needRedraw = 1;
firstDraw = 1;
srand(time(0)); // 初始化随机数种子
}
// 绘制棋盘
void drawBoard() {
if (!needRedraw) return;
if (firstDraw) {
system("cls");
firstDraw = 0;
}
// 游戏信息(显示当前难度)
setCursorPos(0, 0);
printf("===================== 五子棋(人机对战) =====================");
setCursorPos(0, 1);
printf("操作说明:W/A/S/D 移动 | 空格落子 | U悔棋 | R重开 | Q退出");
setCursorPos(0, 2);
printf("难度:%s | 你:黑棋● | AI:白棋○ ",
gameDiff == EASY ? "简单" : (gameDiff == MEDIUM ? "中等" : "困难"));
setCursorPos(0, 3);
printf("=============================================================");
// 列坐标
setCursorPos(0, 5);
printf(" ");
for (int j = 0; j < BOARD_SIZE; j++) {
printf("%2d ", j);
}
// 棋盘主体
for (int i = 0; i < BOARD_SIZE; i++) {
setCursorPos(0, 6 + i);
printf("%2d ", i);
for (int j = 0; j < BOARD_SIZE; j++) {
if (i == currentY && j == currentX) {
printf("■ "); // 玩家光标
} else {
switch (board[i][j]) {
case EMPTY: printf("+ "); break;
case BLACK: printf("● "); break;
case WHITE: printf("○ "); break;
}
}
}
printf(" ");
}
needRedraw = 0;
}
// 检查是否获胜(通用函数)
int checkWin(int x, int y) {
ChessType player = board[y][x];
if (player == EMPTY) return 0;
// 4个检查方向:横、纵、左对角、右对角
int dx[] = {1, 0, 1, 1};
int dy[] = {0, 1, 1, -1};
for (int dir = 0; dir < 4; dir++) {
int count = 1;
// 正方向检查
for (int step = 1; step < 5; step++) {
int nx = x + dx[dir] * step;
int ny = y + dy[dir] * step;
if (nx < 0 || nx >= BOARD_SIZE || ny < 0 || ny >= BOARD_SIZE || board[ny][nx] != player) {
break;
}
count++;
}
// 反方向检查
for (int step = 1; step < 5; step++) {
int nx = x - dx[dir] * step;
int ny = y - dy[dir] * step;
if (nx < 0 || nx >= BOARD_SIZE || ny < 0 || ny >= BOARD_SIZE || board[ny][nx] != player) {
break;
}
count++;
}
if (count >= 5) {
return 1;
}
}
return 0;
}
// AI评分函数(不同难度不同权重)
int evaluatePos(int x, int y, ChessType player) {
if (x < 0 || x >= BOARD_SIZE || y < 0 || y >= BOARD_SIZE || board[y][x] != EMPTY) {
return 0; // 非法位置评分0
}
// 临时落子
board[y][x] = player;
int score = 0;
// 4个方向评分
int dx[] = {1, 0, 1, 1};
int dy[] = {0, 1, 1, -1};
for (int dir = 0; dir < 4; dir++) {
int emptyCount = 0; // 空位数
int chessCount = 0; // 同色棋子数
int blockCount = 0; // 阻挡数
// 正方向
for (int step = 1; step < 5; step++) {
int nx = x + dx[dir] * step;
int ny = y + dy[dir] * step;
if (nx < 0 || nx >= BOARD_SIZE || ny < 0 || ny >= BOARD_SIZE) {
blockCount++;
break;
}
if (board[ny][nx] == player) {
chessCount++;
} else if (board[ny][nx] == EMPTY) {
emptyCount++;
break;
} else {
blockCount++;
break;
}
}
// 反方向
for (int step = 1; step < 5; step++) {
int nx = x - dx[dir] * step;
int ny = y - dy[dir] * step;
if (nx < 0 || nx >= BOARD_SIZE || ny < 0 || ny >= BOARD_SIZE) {
blockCount++;
break;
}
if (board[ny][nx] == player) {
chessCount++;
} else if (board[ny][nx] == EMPTY) {
emptyCount++;
break;
} else {
blockCount++;
break;
}
}
// 不同难度的评分权重
if (gameDiff == EASY) {
// 简单难度:降低评分权重,增加随机性
if (chessCount >= 4) score += MAX_SCORE / 10;
else if (chessCount == 3) score += 1000 / 10;
} else if (gameDiff == MEDIUM) {
// 中等难度:正常权重
if (chessCount >= 4) score += MAX_SCORE;
else if (chessCount == 3 && emptyCount >= 2) score += 10000;
else if (chessCount == 2 && emptyCount >= 2) score += 1000;
} else {
// 困难难度:提高权重,优先攻防
if (chessCount >= 4) score += MAX_SCORE * 2;
else if (chessCount == 3 && emptyCount >= 2) score += 50000;
else if (chessCount == 2 && emptyCount >= 2) score += 5000;
// 额外加分:棋盘中心区域
if (abs(x - BOARD_SIZE/2) <= 2 && abs(y - BOARD_SIZE/2) <= 2) {
score += 500;
}
}
// 封堵玩家的高分点位(困难难度加倍)
if (player == BLACK) {
score *= (gameDiff == HARD ? 3 : 1);
}
}
// 撤销临时落子
board[y][x] = EMPTY;
return score;
}
// AI自动落子(按难度策略)
void aiPlaceChess() {
int bestX = -1, bestY = -1;
int maxScore = MIN_SCORE;
// 简单难度:50%概率随机落子
if (gameDiff == EASY && rand() % 2 == 0) {
do {
bestX = rand() % BOARD_SIZE;
bestY = rand() % BOARD_SIZE;
} while (board[bestY][bestX] != EMPTY);
} else {
// 中/困难难度:评分选点
for (int i = 0; i < BOARD_SIZE; i++) {
for (int j = 0; j < BOARD_SIZE; j++) {
if (board[i][j] != EMPTY) continue;
// 计算AI落子(白棋)和封堵玩家(黑棋)的评分
int aiScore = evaluatePos(j, i, WHITE);
int blockScore = evaluatePos(j, i, BLACK);
int totalScore = aiScore + blockScore;
// 困难难度:优先封堵玩家
if (gameDiff == HARD && blockScore > aiScore) {
totalScore = blockScore * 2;
}
if (totalScore > maxScore) {
maxScore = totalScore;
bestX = j;
bestY = i;
}
}
}
// 兜底随机落子
if (bestX == -1 || bestY == -1) {
do {
bestX = rand() % BOARD_SIZE;
bestY = rand() % BOARD_SIZE;
} while (board[bestY][bestX] != EMPTY);
}
}
// AI落子
lastX = bestX;
lastY = bestY;
board[bestY][bestX] = WHITE;
needRedraw = 1;
// 检查AI是否获胜
if (checkWin(bestX, bestY)) {
drawBoard();
setCursorPos(0, 25);
printf("\nAI获胜!你输了??\n");
printf("按任意键返回难度选择...");
_getch();
selectDifficulty(); // 获胜后返回难度选择
initBoard();
}
}
// 玩家落子操作
void playerPlaceChess() {
// 检查位置合法性
if (currentX < 0 || currentX >= BOARD_SIZE || currentY < 0 || currentY >= BOARD_SIZE) {
return;
}
if (board[currentY][currentX] != EMPTY) {
setCursorPos(0, 25);
printf("该位置已有棋子!按任意键继续... ");
_getch();
setCursorPos(0, 25);
printf(" ");
return;
}
// 玩家落子(黑棋)
lastX = currentX;
lastY = currentY;
board[currentY][currentX] = BLACK;
needRedraw = 1;
// 检查玩家是否获胜
if (checkWin(currentX, currentY)) {
drawBoard();
setCursorPos(0, 25);
printf("\n恭喜你获胜!??\n");
printf("按任意键返回难度选择...");
_getch();
selectDifficulty(); // 获胜后返回难度选择
initBoard();
return;
}
// 玩家落子后,AI自动落子
aiPlaceChess();
}
// 悔棋操作
void regretChess() {
if (lastX == -1 || lastY == -1) {
setCursorPos(0, 25);
printf("没有可悔的步数!按任意键继续... ");
_getch();
setCursorPos(0, 25);
printf(" ");
return;
}
// 撤销玩家落子
board[lastY][lastX] = EMPTY;
needRedraw = 1;
// 查找并撤销AI的上一步落子
int aiLastX = -1, aiLastY = -1;
for (int i = 0; i < BOARD_SIZE; i++) {
for (int j = 0; j < BOARD_SIZE; j++) {
if (board[i][j] == WHITE) {
aiLastX = j;
aiLastY = i;
}
}
}
if (aiLastX != -1 && aiLastY != -1) {
board[aiLastY][aiLastX] = EMPTY;
}
lastX = -1;
lastY = -1;
setCursorPos(0, 25);
printf("悔棋成功!按任意键继续... ");
_getch();
setCursorPos(0, 25);
printf(" ");
needRedraw = 1;
}
// 主游戏循环
void gameLoop() {
initBoard();
hideCursor();
while (!gameOver) {
drawBoard();
// 玩家输入处理
if (_kbhit()) {
char key = _getch();
switch (key) {
case 'w': case 'W': // 上
if (currentY > 0) {
currentY--;
needRedraw = 1;
}
break;
case 's': case 'S': // 下
if (currentY < BOARD_SIZE - 1) {
currentY++;
needRedraw = 1;
}
break;
case 'a': case 'A': // 左
if (currentX > 0) {
currentX--;
needRedraw = 1;
}
break;
case 'd': case 'D': // 右
if (currentX < BOARD_SIZE - 1) {
currentX++;
needRedraw = 1;
}
break;
case ' ': // 落子
playerPlaceChess();
break;
case 'u': case 'U': // 悔棋
regretChess();
break;
case 'r': case 'R': // 重开(保留当前难度)
initBoard();
break;
case 'q': case 'Q': // 退出
gameOver = 1;
setCursorPos(0, 25);
printf("游戏已退出!");
break;
}
}
Sleep(80);
}
}
// 主函数
int main() {
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
if (hConsole != INVALID_HANDLE_VALUE) {
SetConsoleOutputCP(CP_GBK);
}
// 先选择难度,再进入游戏
selectDifficulty();
gameLoop();
return 0;
}